Merge "Make PSS profiling configurable" into main
diff --git a/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/SurfaceFlingerPerfTest.java b/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/SurfaceFlingerPerfTest.java
index f92c297..dca818e 100644
--- a/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/SurfaceFlingerPerfTest.java
+++ b/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/SurfaceFlingerPerfTest.java
@@ -17,10 +17,14 @@
package android.surfaceflinger;
import android.graphics.Bitmap;
+import android.graphics.Canvas;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceControl;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+
import androidx.test.ext.junit.rules.ActivityScenarioRule;
import androidx.test.filters.LargeTest;
@@ -194,4 +198,16 @@
mTransaction.apply(true);
}
}
+
+ @Test
+ public void bufferQueue() throws Exception {
+ SurfaceView testSV = mActivity.mTestSurfaceView;
+ SurfaceHolder holder = testSV.getHolder();
+ holder.getSurface();
+ for (int i = 0; i < sProfilingIterations; i++) {
+ Canvas canvas = holder.lockCanvas();
+ holder.unlockCanvasAndPost(canvas);
+ mTransaction.apply(true);
+ }
+ }
}
diff --git a/core/api/current.txt b/core/api/current.txt
index f5db575..36c2f01 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -9635,9 +9635,16 @@
method @RequiresPermission(android.Manifest.permission.DELIVER_COMPANION_MESSAGES) public final void detachSystemDataTransport(int) throws android.companion.DeviceNotAssociatedException;
method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
method @Deprecated @MainThread public void onDeviceAppeared(@NonNull String);
- method @MainThread public void onDeviceAppeared(@NonNull android.companion.AssociationInfo);
+ method @Deprecated @MainThread public void onDeviceAppeared(@NonNull android.companion.AssociationInfo);
method @Deprecated @MainThread public void onDeviceDisappeared(@NonNull String);
- method @MainThread public void onDeviceDisappeared(@NonNull android.companion.AssociationInfo);
+ method @Deprecated @MainThread public void onDeviceDisappeared(@NonNull android.companion.AssociationInfo);
+ method @MainThread public void onDeviceEvent(@NonNull android.companion.AssociationInfo, int);
+ field public static final int DEVICE_EVENT_BLE_APPEARED = 0; // 0x0
+ field public static final int DEVICE_EVENT_BLE_DISAPPEARED = 1; // 0x1
+ field public static final int DEVICE_EVENT_BT_CONNECTED = 2; // 0x2
+ field public static final int DEVICE_EVENT_BT_DISCONNECTED = 3; // 0x3
+ field public static final int DEVICE_EVENT_SELF_MANAGED_APPEARED = 4; // 0x4
+ field public static final int DEVICE_EVENT_SELF_MANAGED_DISAPPEARED = 5; // 0x5
field public static final String SERVICE_INTERFACE = "android.companion.CompanionDeviceService";
}
diff --git a/core/java/android/companion/CompanionDeviceService.java b/core/java/android/companion/CompanionDeviceService.java
index f660377..03e75e9 100644
--- a/core/java/android/companion/CompanionDeviceService.java
+++ b/core/java/android/companion/CompanionDeviceService.java
@@ -17,6 +17,7 @@
package android.companion;
+import android.annotation.IntDef;
import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -31,13 +32,14 @@
import java.io.InputStream;
import java.io.OutputStream;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
import java.util.concurrent.Executor;
/**
- * A service that receives calls from the system when the associated companion device appears
- * nearby or is connected, as well as when the device is no longer "present" or connected.
- * See {@link #onDeviceAppeared(AssociationInfo)}/{@link #onDeviceDisappeared(AssociationInfo)}.
+ * A service that receives calls from the system with device events.
+ * See {@link #onDeviceEvent(AssociationInfo, int)}.
*
* <p>
* Companion applications must create a service that {@code extends}
@@ -121,6 +123,57 @@
*/
public static final String SERVICE_INTERFACE = "android.companion.CompanionDeviceService";
+ /** @hide */
+ @IntDef(prefix = {"DEVICE_EVENT"}, value = {
+ DEVICE_EVENT_BLE_APPEARED,
+ DEVICE_EVENT_BLE_DISAPPEARED,
+ DEVICE_EVENT_BT_CONNECTED,
+ DEVICE_EVENT_BT_DISCONNECTED,
+ DEVICE_EVENT_SELF_MANAGED_APPEARED,
+ DEVICE_EVENT_SELF_MANAGED_DISAPPEARED
+ })
+
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface DeviceEvent {}
+
+ /**
+ * Companion app receives {@link #onDeviceEvent(AssociationInfo, int)} callback
+ * with this event if the device comes into BLE range.
+ */
+ public static final int DEVICE_EVENT_BLE_APPEARED = 0;
+
+ /**
+ * Companion app receives {@link #onDeviceEvent(AssociationInfo, int)} callback
+ * with this event if the device is no longer in BLE range.
+ */
+ public static final int DEVICE_EVENT_BLE_DISAPPEARED = 1;
+
+ /**
+ * Companion app receives {@link #onDeviceEvent(AssociationInfo, int)} callback
+ * with this event when the bluetooth device is connected.
+ */
+ public static final int DEVICE_EVENT_BT_CONNECTED = 2;
+
+ /**
+ * Companion app receives {@link #onDeviceEvent(AssociationInfo, int)} callback
+ * with this event if the bluetooth device is disconnected.
+ */
+ public static final int DEVICE_EVENT_BT_DISCONNECTED = 3;
+
+ /**
+ * A companion app for a {@link AssociationInfo#isSelfManaged() self-managed} device will
+ * receive the callback {@link #onDeviceEvent(AssociationInfo, int)} if it reports that a
+ * device has appeared on its own.
+ */
+ public static final int DEVICE_EVENT_SELF_MANAGED_APPEARED = 4;
+
+ /**
+ * A companion app for a {@link AssociationInfo#isSelfManaged() self-managed} device will
+ * receive the callback {@link #onDeviceEvent(AssociationInfo, int)} if it reports that a
+ * device has disappeared on its own.
+ */
+ public static final int DEVICE_EVENT_SELF_MANAGED_DISAPPEARED = 5;
+
private final Stub mRemote = new Stub();
/**
@@ -251,7 +304,10 @@
* Called by system whenever a device associated with this app is connected.
*
* @param associationInfo A record for the companion device.
+ *
+ * @deprecated please override {@link #onDeviceEvent(AssociationInfo, int)} instead.
*/
+ @Deprecated
@MainThread
public void onDeviceAppeared(@NonNull AssociationInfo associationInfo) {
if (!associationInfo.isSelfManaged()) {
@@ -263,7 +319,10 @@
* Called by system whenever a device associated with this app is disconnected.
*
* @param associationInfo A record for the companion device.
+ *
+ * @deprecated please override {@link #onDeviceEvent(AssociationInfo, int)} instead.
*/
+ @Deprecated
@MainThread
public void onDeviceDisappeared(@NonNull AssociationInfo associationInfo) {
if (!associationInfo.isSelfManaged()) {
@@ -271,6 +330,30 @@
}
}
+ /**
+ * Called by the system during device events.
+ *
+ * <p>E.g. Event {@link #DEVICE_EVENT_BLE_APPEARED} will be called when the associated
+ * companion device comes into BLE range.
+ * <p>Event {@link #DEVICE_EVENT_BLE_DISAPPEARED} will be called when the associated
+ * companion device is no longer in BLE range.
+ * <p> Event {@link #DEVICE_EVENT_BT_CONNECTED} will be called when the associated
+ * companion device is connected.
+ * <p>Event {@link #DEVICE_EVENT_BT_DISCONNECTED} will be called when the associated
+ * companion device is disconnected.
+ * Note that app must receive {@link #DEVICE_EVENT_BLE_APPEARED} first before
+ * {@link #DEVICE_EVENT_BLE_DISAPPEARED} and {@link #DEVICE_EVENT_BT_CONNECTED}
+ * before {@link #DEVICE_EVENT_BT_DISCONNECTED}.
+ *
+ * @param associationInfo A record for the companion device.
+ * @param event Associated companion device's event.
+ */
+ @MainThread
+ public void onDeviceEvent(@NonNull AssociationInfo associationInfo,
+ @DeviceEvent int event) {
+ // Do nothing. Companion apps can override this function.
+ }
+
@Nullable
@Override
public final IBinder onBind(@NonNull Intent intent) {
@@ -304,5 +387,11 @@
public void onDeviceDisappeared(AssociationInfo associationInfo) {
mMainHandler.postAtFrontOfQueue(() -> mService.onDeviceDisappeared(associationInfo));
}
+
+ @Override
+ public void onDeviceEvent(AssociationInfo associationInfo, int event) {
+ mMainHandler.postAtFrontOfQueue(
+ () -> mService.onDeviceEvent(associationInfo, event));
+ }
}
}
diff --git a/core/java/android/companion/ICompanionDeviceService.aidl b/core/java/android/companion/ICompanionDeviceService.aidl
index fa68508..2a311bf 100644
--- a/core/java/android/companion/ICompanionDeviceService.aidl
+++ b/core/java/android/companion/ICompanionDeviceService.aidl
@@ -22,4 +22,5 @@
oneway interface ICompanionDeviceService {
void onDeviceAppeared(in AssociationInfo associationInfo);
void onDeviceDisappeared(in AssociationInfo associationInfo);
+ void onDeviceEvent(in AssociationInfo associationInfo, int state);
}
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index a0bbeb5..c86ccfd 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -1483,6 +1483,12 @@
// proper SQL syntax for us.
SQLiteQueryBuilder qBuilder = new SQLiteQueryBuilder();
+ // Guard against SQL injection attacks
+ qBuilder.setStrict(true);
+ qBuilder.setProjectionMap(MAP_OF_QUERYABLE_COLUMNS);
+ qBuilder.setStrictColumns(true);
+ qBuilder.setStrictGrammar(true);
+
// Set the table we're querying.
qBuilder.setTables(DATABASE_TABLE_NAME);
@@ -1546,6 +1552,12 @@
// proper SQL syntax for us.
SQLiteQueryBuilder qBuilder = new SQLiteQueryBuilder();
+ // Guard against SQL injection attacks
+ qBuilder.setStrict(true);
+ qBuilder.setProjectionMap(MAP_OF_QUERYABLE_COLUMNS);
+ qBuilder.setStrictColumns(true);
+ qBuilder.setStrictGrammar(true);
+
// Set the table we're querying.
qBuilder.setTables(DATABASE_TABLE_NAME);
diff --git a/core/java/android/database/sqlite/SQLiteQueryBuilder.java b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
index e9c59f5..2061c2b 100644
--- a/core/java/android/database/sqlite/SQLiteQueryBuilder.java
+++ b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
@@ -48,6 +48,15 @@
/**
* This is a convenience class that helps build SQL queries to be sent to
* {@link SQLiteDatabase} objects.
+ * <p>
+ * This class is often used to compose a SQL query from client-supplied fragments. Best practice
+ * to protect against invalid or illegal SQL is to set the following:
+ * <ul>
+ * <li>{@link #setStrict} true.
+ * <li>{@link #setProjectionMap} with the list of queryable columns.
+ * <li>{@link #setStrictColumns} true.
+ * <li>{@link #setStrictGrammar} true.
+ * </ul>
*/
public class SQLiteQueryBuilder {
private static final String TAG = "SQLiteQueryBuilder";
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index d8d59b4..2abf02e 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2120,6 +2120,21 @@
"android.settings.MANAGE_MORE_DEFAULT_APPS_SETTINGS";
/**
+ * Activity Action: Show app screen size list settings for user to override app aspect
+ * ratio.
+ * <p>
+ * In some cases, a matching Activity may not exist, so ensure you
+ * safeguard against this.
+ * <p>
+ * Can include the following extra {@link android.content.Intent#EXTRA_PACKAGE_NAME} specifying
+ * the name of the package to scroll to in the page.
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_MANAGE_USER_ASPECT_RATIO_SETTINGS =
+ "android.settings.MANAGE_USER_ASPECT_RATIO_SETTINGS";
+
+ /**
* Activity Action: Show notification settings.
*
* @hide
diff --git a/core/java/android/service/voice/AbstractDetector.java b/core/java/android/service/voice/AbstractDetector.java
index 8648e38..7af7fe6 100644
--- a/core/java/android/service/voice/AbstractDetector.java
+++ b/core/java/android/service/voice/AbstractDetector.java
@@ -65,6 +65,13 @@
*/
private final IBinder mToken = new Binder();
+ /**
+ * A flag controls whether attributionTag will be passed into the Identity.
+ * TODO(b/289087412): This flag will be converted and confirm to the trunk stable flag
+ * configuration.
+ */
+ static final boolean IS_IDENTITY_WITH_ATTRIBUTION_TAG = false;
+
AbstractDetector(
IVoiceInteractionManagerService managerService,
Executor executor,
@@ -153,12 +160,16 @@
@Nullable PersistableBundle options,
@Nullable SharedMemory sharedMemory,
@NonNull IHotwordRecognitionStatusCallback callback,
- int detectorType) {
+ int detectorType,
+ @Nullable String attributionTag) {
if (DEBUG) {
Slog.d(TAG, "initAndVerifyDetector()");
}
Identity identity = new Identity();
identity.packageName = ActivityThread.currentOpPackageName();
+ if (IS_IDENTITY_WITH_ATTRIBUTION_TAG) {
+ identity.attributionTag = attributionTag;
+ }
try {
mManagerService.initAndVerifyDetector(identity, options, sharedMemory, mToken, callback,
detectorType);
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index 9d28334..21f676e 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -324,6 +324,7 @@
private final Handler mHandler;
private final IBinder mBinder = new Binder();
private final boolean mSupportSandboxedDetectionService;
+ private final String mAttributionTag;
@GuardedBy("mLock")
private boolean mIsAvailabilityOverriddenByTestApi = false;
@@ -846,13 +847,17 @@
* @param targetSdkVersion The target SDK version.
* @param SupportSandboxedDetectionService {@code true} if HotwordDetectionService should be
* triggered, otherwise {@code false}.
+ * @param attributionTag an optional attribution tag passed form the
+ * {@link VoiceInteractionService} context via the
+ * {@link createAlwaysOnHotwordDetectorInternal(String, Locale, boolean, PersistableBundle,
+ * SharedMemory, ModuleProperties, Executor, Callback)}.
*
* @hide
*/
public AlwaysOnHotwordDetector(String text, Locale locale, Executor executor, Callback callback,
KeyphraseEnrollmentInfo keyphraseEnrollmentInfo,
IVoiceInteractionManagerService modelManagementService, int targetSdkVersion,
- boolean supportSandboxedDetectionService) {
+ boolean supportSandboxedDetectionService, @Nullable String attributionTag) {
super(modelManagementService, executor, callback);
mHandler = new MyHandler(Looper.getMainLooper());
@@ -865,6 +870,7 @@
mInternalCallback = new SoundTriggerListener(mHandler);
mModelManagementService = modelManagementService;
mSupportSandboxedDetectionService = supportSandboxedDetectionService;
+ mAttributionTag = attributionTag;
}
// Do nothing. This method should not be abstract.
@@ -876,11 +882,14 @@
@Nullable SoundTrigger.ModuleProperties moduleProperties) {
if (mSupportSandboxedDetectionService) {
initAndVerifyDetector(options, sharedMemory, mInternalCallback,
- DETECTOR_TYPE_TRUSTED_HOTWORD_DSP);
+ DETECTOR_TYPE_TRUSTED_HOTWORD_DSP, mAttributionTag);
}
try {
Identity identity = new Identity();
identity.packageName = ActivityThread.currentOpPackageName();
+ if (IS_IDENTITY_WITH_ATTRIBUTION_TAG) {
+ identity.attributionTag = mAttributionTag;
+ }
if (moduleProperties == null) {
moduleProperties = mModelManagementService
.listModuleProperties(identity)
diff --git a/core/java/android/service/voice/SoftwareHotwordDetector.java b/core/java/android/service/voice/SoftwareHotwordDetector.java
index 7ab4faf..128bc0d 100644
--- a/core/java/android/service/voice/SoftwareHotwordDetector.java
+++ b/core/java/android/service/voice/SoftwareHotwordDetector.java
@@ -56,12 +56,14 @@
private final HotwordDetector.Callback mCallback;
private final AudioFormat mAudioFormat;
private final Executor mExecutor;
+ private final String mAttributionTag;
SoftwareHotwordDetector(
IVoiceInteractionManagerService managerService,
AudioFormat audioFormat,
Executor executor,
- HotwordDetector.Callback callback) {
+ HotwordDetector.Callback callback,
+ String attributionTag) {
super(managerService, executor, callback);
mManagerService = managerService;
@@ -69,13 +71,14 @@
mCallback = callback;
mExecutor = executor != null ? executor : new HandlerExecutor(
new Handler(Looper.getMainLooper()));
+ mAttributionTag = attributionTag;
}
@Override
void initialize(@Nullable PersistableBundle options, @Nullable SharedMemory sharedMemory) {
initAndVerifyDetector(options, sharedMemory,
new InitializationStateListener(mExecutor, mCallback),
- DETECTOR_TYPE_TRUSTED_HOTWORD_SOFTWARE);
+ DETECTOR_TYPE_TRUSTED_HOTWORD_SOFTWARE, mAttributionTag);
}
void onDetectorRemoteException() {
diff --git a/core/java/android/service/voice/VisualQueryDetector.java b/core/java/android/service/voice/VisualQueryDetector.java
index 93b7964..9e0eb4b 100644
--- a/core/java/android/service/voice/VisualQueryDetector.java
+++ b/core/java/android/service/voice/VisualQueryDetector.java
@@ -60,15 +60,17 @@
private final Executor mExecutor;
private final IVoiceInteractionManagerService mManagerService;
private final VisualQueryDetectorInitializationDelegate mInitializationDelegate;
+ private final String mAttributionTag;
VisualQueryDetector(
IVoiceInteractionManagerService managerService,
@NonNull @CallbackExecutor Executor executor,
- Callback callback) {
+ Callback callback, @Nullable String attributionTag) {
mManagerService = managerService;
mCallback = callback;
mExecutor = executor;
mInitializationDelegate = new VisualQueryDetectorInitializationDelegate();
+ mAttributionTag = attributionTag;
}
/**
@@ -246,7 +248,7 @@
void initialize(@Nullable PersistableBundle options, @Nullable SharedMemory sharedMemory) {
initAndVerifyDetector(options, sharedMemory,
new InitializationStateListener(mExecutor, mCallback),
- DETECTOR_TYPE_VISUAL_QUERY_DETECTOR);
+ DETECTOR_TYPE_VISUAL_QUERY_DETECTOR, mAttributionTag);
}
@Override
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index ab9ae0a..8cec17f 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -734,7 +734,7 @@
AlwaysOnHotwordDetector dspDetector = new AlwaysOnHotwordDetector(keyphrase, locale,
executor, callback, mKeyphraseEnrollmentInfo, mSystemService,
getApplicationContext().getApplicationInfo().targetSdkVersion,
- supportHotwordDetectionService);
+ supportHotwordDetectionService, getAttributionTag());
mActiveDetectors.add(dspDetector);
try {
@@ -895,7 +895,7 @@
SoftwareHotwordDetector softwareHotwordDetector =
new SoftwareHotwordDetector(mSystemService, /* audioFormat= */ null,
- executor, callback);
+ executor, callback, getAttributionTag());
mActiveDetectors.add(softwareHotwordDetector);
try {
@@ -965,7 +965,8 @@
}
VisualQueryDetector visualQueryDetector =
- new VisualQueryDetector(mSystemService, executor, callback);
+ new VisualQueryDetector(mSystemService, executor, callback,
+ getAttributionTag());
HotwordDetector visualQueryDetectorInitializationDelegate =
visualQueryDetector.getInitializationDelegate();
mActiveDetectors.add(visualQueryDetectorInitializationDelegate);
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index e47fab4..c7e5453 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -41,6 +41,9 @@
import android.app.WallpaperColors;
import android.app.WallpaperInfo;
import android.app.WallpaperManager;
+import android.app.compat.CompatChanges;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.Intent;
@@ -194,6 +197,18 @@
// TODO (b/287037772) remove this flag and the forceReport argument in reportVisibility
private boolean mIsWearOs;
+ /**
+ * Wear products currently force a slight scaling transition to wallpapers
+ * when the QSS is opened. However, on Wear 6 (SDK 35) and above, 1P watch faces
+ * will be expected to either implement their own scaling, or to override this
+ * method to allow the WallpaperController to continue to scale for them.
+ *
+ * @hide
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ public static final long WEAROS_WALLPAPER_HANDLES_SCALING = 272527315L;
+
static final class WallpaperCommand {
String action;
int x;
@@ -601,7 +616,7 @@
* @hide
*/
public boolean shouldZoomOutWallpaper() {
- return false;
+ return mIsWearOs && !CompatChanges.isChangeEnabled(WEAROS_WALLPAPER_HANDLES_SCALING);
}
/**
diff --git a/core/java/com/android/internal/os/BatteryStatsHistory.java b/core/java/com/android/internal/os/BatteryStatsHistory.java
index 0a9bab5..1cde742 100644
--- a/core/java/com/android/internal/os/BatteryStatsHistory.java
+++ b/core/java/com/android/internal/os/BatteryStatsHistory.java
@@ -253,7 +253,11 @@
public void traceCounter(@NonNull String name, int value) {
Trace.traceCounter(Trace.TRACE_TAG_POWER, name, value);
if (mShouldSetProperty) {
- SystemProperties.set("debug.tracing." + name, Integer.toString(value));
+ try {
+ SystemProperties.set("debug.tracing." + name, Integer.toString(value));
+ } catch (RuntimeException e) {
+ Slog.e(TAG, "Failed to set debug.tracing." + name, e);
+ }
}
}
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 0c6d6f9..965277c 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -196,7 +196,8 @@
public static final int PROFILEABLE = 1 << 24;
/**
- * Enable ptrace. This is enabled on eng or userdebug builds, or if the app is debuggable.
+ * Enable ptrace. This is enabled on eng, if the app is debuggable, or if
+ * the persist.debug.ptrace.enabled property is set.
*/
public static final int DEBUG_ENABLE_PTRACE = 1 << 25;
@@ -1020,20 +1021,35 @@
"persist.debug.dalvik.vm.jdwp.enabled").equals("1");
/**
+ * This will enable ptrace by default for all apps. It is OK to cache this property
+ * because we expect to reboot the system whenever this property changes
+ */
+ private static final boolean ENABLE_PTRACE = SystemProperties.get(
+ "persist.debug.ptrace.enabled").equals("1");
+
+ /**
* Applies debugger system properties to the zygote arguments.
*
- * For eng builds all apps are debuggable. On userdebug and user builds
- * if persist.debug.dalvik.vm.jdwp.enabled is 1 all apps are
- * debuggable. Otherwise, the debugger state is specified via the
- * "--enable-jdwp" flag in the spawn request.
+ * For eng builds all apps are debuggable with JDWP and ptrace.
+ *
+ * On userdebug builds if persist.debug.dalvik.vm.jdwp.enabled
+ * is 1 all apps are debuggable with JDWP and ptrace. Otherwise, the
+ * debugger state is specified via the "--enable-jdwp" flag in the
+ * spawn request.
+ *
+ * On userdebug builds if persist.debug.ptrace.enabled is 1 all
+ * apps are debuggable with ptrace.
*
* @param args non-null; zygote spawner args
*/
static void applyDebuggerSystemProperty(ZygoteArguments args) {
- if (Build.IS_ENG || ENABLE_JDWP) {
+ if (Build.IS_ENG || (Build.IS_USERDEBUG && ENABLE_JDWP)) {
args.mRuntimeFlags |= Zygote.DEBUG_ENABLE_JDWP;
+ // Also enable ptrace when JDWP is enabled for consistency with
+ // before persist.debug.ptrace.enabled existed.
+ args.mRuntimeFlags |= Zygote.DEBUG_ENABLE_PTRACE;
}
- if (RoSystemProperties.DEBUGGABLE) {
+ if (Build.IS_ENG || (Build.IS_USERDEBUG && ENABLE_PTRACE)) {
args.mRuntimeFlags |= Zygote.DEBUG_ENABLE_PTRACE;
}
}
@@ -1057,7 +1073,8 @@
int peerUid = peer.getUid();
if (args.mInvokeWith != null && peerUid != 0
- && (args.mRuntimeFlags & Zygote.DEBUG_ENABLE_JDWP) == 0) {
+ && (args.mRuntimeFlags
+ & (Zygote.DEBUG_ENABLE_JDWP | Zygote.DEBUG_ENABLE_PTRACE)) == 0) {
throw new ZygoteSecurityException("Peer is permitted to specify an "
+ "explicit invoke-with wrapper command only for debuggable "
+ "applications.");
diff --git a/core/res/res/values-watch/config.xml b/core/res/res/values-watch/config.xml
index cf0488b..b0d9b67 100644
--- a/core/res/res/values-watch/config.xml
+++ b/core/res/res/values-watch/config.xml
@@ -33,6 +33,14 @@
<!-- Maximum velocity to initiate a fling, as measured in dips per second. -->
<dimen name="config_viewMaxFlingVelocity">8000dp</dimen>
+ <!-- Minimum velocity (absolute value) to initiate a fling from a rotary encoder device, as
+ measured in dips per second. Setting this to -1dp disables rotary encoder fling. -->
+ <dimen name="config_viewMinRotaryEncoderFlingVelocity">500dp</dimen>
+
+ <!-- Maximum velocity (absolute value) to initiate a fling from a rotary encoder device, as
+ measured in dips per second. Setting this to -1dp disables rotary encoder fling. -->
+ <dimen name="config_viewMaxRotaryEncoderFlingVelocity">8000dp</dimen>
+
<!-- Number of notifications to keep in the notification service historical archive.
Reduced intentionally for watches to retain minimal memory footprint -->
<integer name="config_notificationServiceArchiveSize">1</integer>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index d6ee57c..5806e93 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -4454,6 +4454,7 @@
<java-symbol type="string" name="notification_history_title_placeholder" />
+ <java-symbol type="dimen" name="config_wallpaperMinScale"/>
<!-- The max scale for the wallpaper when it's zoomed in -->
<java-symbol type="dimen" name="config_wallpaperMaxScale"/>
diff --git a/data/keyboards/Vendor_0957_Product_0001.kl b/data/keyboards/Vendor_0957_Product_0001.kl
index 893c87d..354f10a 100644
--- a/data/keyboards/Vendor_0957_Product_0001.kl
+++ b/data/keyboards/Vendor_0957_Product_0001.kl
@@ -43,6 +43,8 @@
key 10 9
key 11 0
+key usage 0x00070037 PERIOD
+
# custom keys
key usage 0x000c01BB TV_INPUT
key usage 0x000c0186 MACRO_1 WAKE
@@ -51,7 +53,6 @@
key usage 0x000c0061 CAPTIONS
key usage 0x000c01BD INFO
-key usage 0x000c0037 PERIOD
key usage 0x000c0069 PROG_RED
key usage 0x000c006A PROG_GREEN
diff --git a/libs/WindowManager/Shell/res/drawable/decor_desktop_mode_maximize_button_dark.xml b/libs/WindowManager/Shell/res/drawable/decor_desktop_mode_maximize_button_dark.xml
new file mode 100644
index 0000000..02b7075
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/decor_desktop_mode_maximize_button_dark.xml
@@ -0,0 +1,26 @@
+<?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.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:tint="?attr/colorControlNormal"
+ android:viewportHeight="960"
+ android:viewportWidth="960">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M180,840Q156,840 138,822Q120,804 120,780L120,180Q120,156 138,138Q156,120 180,120L780,120Q804,120 822,138Q840,156 840,180L840,780Q840,804 822,822Q804,840 780,840L180,840ZM180,780L780,780Q780,780 780,780Q780,780 780,780L780,277L180,277L180,780Q180,780 180,780Q180,780 180,780Z" />
+</vector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_app_controls_window_decor.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_app_controls_window_decor.xml
index fb1980a..7e0c207 100644
--- a/libs/WindowManager/Shell/res/layout/desktop_mode_app_controls_window_decor.xml
+++ b/libs/WindowManager/Shell/res/layout/desktop_mode_app_controls_window_decor.xml
@@ -78,6 +78,19 @@
android:layout_weight="1"/>
<ImageButton
+ android:id="@+id/maximize_window"
+ android:layout_width="40dp"
+ android:layout_height="40dp"
+ android:padding="9dp"
+ android:layout_marginEnd="8dp"
+ android:contentDescription="@string/maximize_button_text"
+ android:src="@drawable/decor_desktop_mode_maximize_button_dark"
+ android:scaleType="fitCenter"
+ android:gravity="end"
+ android:background="@null"
+ android:tint="@color/desktop_mode_caption_maximize_button_dark"/>
+
+ <ImageButton
android:id="@+id/close_window"
android:layout_width="40dp"
android:layout_height="40dp"
diff --git a/libs/WindowManager/Shell/res/values/colors.xml b/libs/WindowManager/Shell/res/values/colors.xml
index f2a0785..b2ec98b 100644
--- a/libs/WindowManager/Shell/res/values/colors.xml
+++ b/libs/WindowManager/Shell/res/values/colors.xml
@@ -64,6 +64,8 @@
<color name="desktop_mode_caption_expand_button_dark">#48473A</color>
<color name="desktop_mode_caption_close_button_light">#EFF1F2</color>
<color name="desktop_mode_caption_close_button_dark">#1C1C17</color>
+ <color name="desktop_mode_caption_maximize_button_light">#EFF1F2</color>
+ <color name="desktop_mode_caption_maximize_button_dark">#1C1C17</color>
<color name="desktop_mode_caption_app_name_light">#EFF1F2</color>
<color name="desktop_mode_caption_app_name_dark">#1C1C17</color>
<color name="desktop_mode_caption_menu_text_color">#191C1D</color>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
index 6718565..e698601 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
@@ -312,9 +312,13 @@
+ " bubble=" + getBubbleKey());
}
if (mBubble != null) {
- // Must post because this is called from a binder thread.
- post(() -> mController.removeBubble(
- mBubble.getKey(), Bubbles.DISMISS_TASK_FINISHED));
+ mController.removeBubble(mBubble.getKey(), Bubbles.DISMISS_TASK_FINISHED);
+ }
+ if (mTaskView != null) {
+ // Release the surface
+ mTaskView.release();
+ removeView(mTaskView);
+ mTaskView = null;
}
}
@@ -1058,8 +1062,10 @@
}
/**
- * Cleans up anything related to the task and {@code TaskView}. If this view should be reused
- * after this method is called, then
+ * Cleans up anything related to the task. The TaskView itself is released after the task
+ * has been removed.
+ *
+ * If this view should be reused after this method is called, then
* {@link #initialize(BubbleController, BubbleStackView, boolean)} must be invoked first.
*/
public void cleanUpExpandedState() {
@@ -1081,10 +1087,7 @@
}
}
if (mTaskView != null) {
- // Release the surface & other task view related things
- mTaskView.release();
- removeView(mTaskView);
- mTaskView = null;
+ mTaskView.setVisibility(GONE);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java
index d972f48..16c3960 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java
@@ -16,7 +16,6 @@
package com.android.wm.shell.dagger.pip;
-import android.annotation.Nullable;
import android.content.Context;
import android.os.Handler;
@@ -229,7 +228,6 @@
@WMSingleton
@Provides
- @Nullable
static PipTransition providePipTransition(Context context,
ShellInit shellInit, ShellTaskOrganizer shellTaskOrganizer, Transitions transitions,
PipAnimationController pipAnimationController, PipBoundsAlgorithm pipBoundsAlgorithm,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/PipModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/PipModule.java
index 2ded4a3..04032bb1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/PipModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/PipModule.java
@@ -36,10 +36,13 @@
public abstract class PipModule {
@WMSingleton
@Provides
- @Nullable
static PipTransitionController providePipTransitionController(
com.android.wm.shell.pip.PipTransition legacyPipTransition,
- com.android.wm.shell.pip2.PipTransition newPipTransition) {
- return PipUtils.isPip2ExperimentEnabled() ? newPipTransition : legacyPipTransition;
+ @Nullable com.android.wm.shell.pip2.PipTransition newPipTransition) {
+ if (PipUtils.isPip2ExperimentEnabled() && newPipTransition != null) {
+ return newPipTransition;
+ } else {
+ return legacyPipTransition;
+ }
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
index 39b6675..88a81fc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
@@ -604,7 +604,8 @@
} else if (change.getMode() == TRANSIT_CHANGE) {
// Finish recents animation if the display is changed, so the default
// transition handler can play the animation such as rotation effect.
- if (change.hasFlags(TransitionInfo.FLAG_IS_DISPLAY)) {
+ if (change.hasFlags(TransitionInfo.FLAG_IS_DISPLAY)
+ && info.getType() == TRANSIT_CHANGE) {
// This call to cancel will use the screenshots taken preemptively in
// handleMidTransitionRequest() prior to the display changing
cancel(mWillFinishToHome, true /* withScreenshots */, "display change");
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTaskController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTaskController.java
index 064af04..a743e99 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTaskController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTaskController.java
@@ -317,18 +317,12 @@
// we know about -- so leave clean-up here even if shell transitions are enabled.
if (mTaskToken == null || !mTaskToken.equals(taskInfo.token)) return;
- if (mListener != null) {
- final int taskId = taskInfo.taskId;
- mListenerExecutor.execute(() -> {
- mListener.onTaskRemovalStarted(taskId);
- });
- }
- mTaskOrganizer.setInterceptBackPressedOnTaskRoot(mTaskToken, false);
+ final SurfaceControl taskLeash = mTaskLeash;
+ handleAndNotifyTaskRemoval(mTaskInfo);
// Unparent the task when this surface is destroyed
- mTransaction.reparent(mTaskLeash, null).apply();
+ mTransaction.reparent(taskLeash, null).apply();
resetTaskInfo();
- mTaskViewBase.onTaskVanished(taskInfo);
}
@Override
@@ -498,6 +492,20 @@
}
}
+ /** Notifies listeners of a task being removed and stops intercepting back presses on it. */
+ private void handleAndNotifyTaskRemoval(ActivityManager.RunningTaskInfo taskInfo) {
+ if (taskInfo != null) {
+ if (mListener != null) {
+ final int taskId = taskInfo.taskId;
+ mListenerExecutor.execute(() -> {
+ mListener.onTaskRemovalStarted(taskId);
+ });
+ }
+ mTaskViewBase.onTaskVanished(taskInfo);
+ mTaskOrganizer.setInterceptBackPressedOnTaskRoot(taskInfo.token, false);
+ }
+ }
+
/** Returns the task info for the task in the TaskView. */
@Nullable
public ActivityManager.RunningTaskInfo getTaskInfo() {
@@ -523,18 +531,12 @@
*/
void cleanUpPendingTask() {
if (mPendingInfo != null) {
- if (mListener != null) {
- final int taskId = mPendingInfo.taskId;
- mListenerExecutor.execute(() -> {
- mListener.onTaskRemovalStarted(taskId);
- });
- }
- mTaskViewBase.onTaskVanished(mPendingInfo);
- mTaskOrganizer.setInterceptBackPressedOnTaskRoot(mPendingInfo.token, false);
+ final ActivityManager.RunningTaskInfo pendingInfo = mPendingInfo;
+ handleAndNotifyTaskRemoval(pendingInfo);
// Make sure the task is removed
WindowContainerTransaction wct = new WindowContainerTransaction();
- wct.removeTask(mPendingInfo.token);
+ wct.removeTask(pendingInfo.token);
mTaskViewTransitions.closeTaskView(wct, this);
}
resetTaskInfo();
@@ -559,16 +561,7 @@
* is used instead.
*/
void prepareCloseAnimation() {
- if (mTaskToken != null) {
- if (mListener != null) {
- final int taskId = mTaskInfo.taskId;
- mListenerExecutor.execute(() -> {
- mListener.onTaskRemovalStarted(taskId);
- });
- }
- mTaskViewBase.onTaskVanished(mTaskInfo);
- mTaskOrganizer.setInterceptBackPressedOnTaskRoot(mTaskToken, false);
- }
+ handleAndNotifyTaskRemoval(mTaskInfo);
resetTaskInfo();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
index d978eaf..d07d2b7b6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
@@ -346,7 +346,7 @@
.setFrameScale(1)
.setPixelFormat(PixelFormat.RGBA_8888)
.setChildrenOnly(true)
- .setAllowProtected(true)
+ .setAllowProtected(false)
.setCaptureSecureLayers(true)
.build();
final ScreenCapture.ScreenshotHardwareBuffer edgeBuffer =
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 4cc755b..2b19da2 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
@@ -374,6 +374,11 @@
mDesktopTasksController.ifPresent(c -> c.moveToNextDisplay(mTaskId));
decoration.closeHandleMenu();
}
+ } else if (id == R.id.maximize_window) {
+ final RunningTaskInfo taskInfo = decoration.mTaskInfo;
+ mDesktopTasksController.ifPresent(c -> c.toggleDesktopTaskSize(
+ taskInfo, decoration));
+ decoration.closeHandleMenu();
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt
index b67acd5..672e57a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt
@@ -28,6 +28,7 @@
private val openMenuButton: View = rootView.findViewById(R.id.open_menu_button)
private val closeWindowButton: ImageButton = rootView.findViewById(R.id.close_window)
private val expandMenuButton: ImageButton = rootView.findViewById(R.id.expand_menu_button)
+ private val maximizeWindowButton: ImageButton = rootView.findViewById(R.id.maximize_window)
private val appNameTextView: TextView = rootView.findViewById(R.id.application_name)
private val appIconImageView: ImageView = rootView.findViewById(R.id.application_icon)
@@ -37,6 +38,7 @@
openMenuButton.setOnClickListener(onCaptionButtonClickListener)
openMenuButton.setOnTouchListener(onCaptionTouchListener)
closeWindowButton.setOnClickListener(onCaptionButtonClickListener)
+ maximizeWindowButton.setOnClickListener(onCaptionButtonClickListener)
closeWindowButton.setOnTouchListener(onCaptionTouchListener)
appNameTextView.text = appName
appIconImageView.setImageDrawable(appIcon)
@@ -49,6 +51,8 @@
closeWindowButton.imageTintList = ColorStateList.valueOf(
getCaptionCloseButtonColor(taskInfo))
+ maximizeWindowButton.imageTintList = ColorStateList.valueOf(
+ getCaptionMaximizeButtonColor(taskInfo))
expandMenuButton.imageTintList = ColorStateList.valueOf(
getCaptionExpandButtonColor(taskInfo))
appNameTextView.setTextColor(getCaptionAppNameTextColor(taskInfo))
@@ -70,6 +74,14 @@
}
}
+ private fun getCaptionMaximizeButtonColor(taskInfo: RunningTaskInfo): Int {
+ return if (shouldUseLightCaptionColors(taskInfo)) {
+ context.getColor(R.color.desktop_mode_caption_maximize_button_light)
+ } else {
+ context.getColor(R.color.desktop_mode_caption_maximize_button_dark)
+ }
+ }
+
private fun getCaptionExpandButtonColor(taskInfo: RunningTaskInfo): Int {
return if (shouldUseLightCaptionColors(taskInfo)) {
context.getColor(R.color.desktop_mode_caption_expand_button_light)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt
index 67d5718..1e5e42f 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt
@@ -66,7 +66,8 @@
*/
@Postsubmit
@Test
- fun letterboxAppFocusedAtEnd() = flicker.assertEventLog { focusChanges(letterboxApp.`package`) }
+ fun letterboxAppFocusedAtEnd() =
+ flicker.assertEventLog { focusChanges(letterboxApp.packageName) }
@Postsubmit
@Test
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt
index 5c7d1d8..97147a3 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt
@@ -47,7 +47,7 @@
private val uid =
context.packageManager
- .getApplicationInfo(testApp.`package`, PackageManager.ApplicationInfoFlags.of(0))
+ .getApplicationInfo(testApp.packageName, PackageManager.ApplicationInfoFlags.of(0))
.uid
@JvmOverloads
@@ -57,7 +57,7 @@
return {
setup {
notifyManager.setBubblesAllowed(
- testApp.`package`,
+ testApp.packageName,
uid,
NotificationManager.BUBBLE_PREFERENCE_ALL
)
@@ -68,7 +68,7 @@
teardown {
notifyManager.setBubblesAllowed(
- testApp.`package`,
+ testApp.packageName,
uid,
NotificationManager.BUBBLE_PREFERENCE_NONE
)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTransition.kt
index 6d20740..dfa3696 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTransition.kt
@@ -117,7 +117,7 @@
@Presubmit
@Test
open fun focusChanges() {
- flicker.assertEventLog { this.focusChanges(pipApp.`package`, "NexusLauncherActivity") }
+ flicker.assertEventLog { this.focusChanges(pipApp.packageName, "NexusLauncherActivity") }
}
companion object {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/PipAppHelperTv.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/PipAppHelperTv.kt
index 000ae8f..c6cbcd0 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/PipAppHelperTv.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/PipAppHelperTv.kt
@@ -26,7 +26,7 @@
/** Helper class for PIP app on AndroidTV */
open class PipAppHelperTv(instrumentation: Instrumentation) : PipAppHelper(instrumentation) {
- private val appSelector = By.pkg(`package`).depth(0)
+ private val appSelector = By.pkg(packageName).depth(0)
val ui: UiObject2?
get() = uiDevice.findObject(appSelector)
@@ -46,7 +46,7 @@
}
override fun clickObject(resId: String) {
- val selector = By.res(`package`, resId)
+ val selector = By.res(packageName, resId)
focusOnObject(selector) || error("Could not focus on `$resId` object")
uiDevice.pressDPadCenter()
}
@@ -68,7 +68,7 @@
}
fun waitUntilClosed(): Boolean {
- val appSelector = By.pkg(`package`).depth(0)
+ val appSelector = By.pkg(packageName).depth(0)
return uiDevice.wait(Until.gone(appSelector), APP_CLOSE_WAIT_TIME_MS)
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromAllApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromAllApps.kt
index a3aae85..9b43816 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromAllApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromAllApps.kt
@@ -61,7 +61,7 @@
tapl.launchedAppState.taskbar
.openAllApps()
.getAppIcon(secondaryApp.appName)
- .dragToSplitscreen(secondaryApp.`package`, primaryApp.`package`)
+ .dragToSplitscreen(secondaryApp.packageName, primaryApp.packageName)
SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromShortcut.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromShortcut.kt
index 5d67dc7..76fbf60 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromShortcut.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromShortcut.kt
@@ -63,7 +63,7 @@
.getAppIcon(secondaryApp.appName)
.openDeepShortcutMenu()
.getMenuItem("Split Screen Secondary Activity")
- .dragToSplitscreen(secondaryApp.`package`, primaryApp.`package`)
+ .dragToSplitscreen(secondaryApp.packageName, primaryApp.packageName)
SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
// TODO: Do we want this check in here? Add to the other tests?
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromTaskbar.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromTaskbar.kt
index ae5bb68..f8e43f1 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromTaskbar.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromTaskbar.kt
@@ -61,7 +61,7 @@
open fun enterSplitScreenByDragFromTaskbar() {
tapl.launchedAppState.taskbar
.getAppIcon(secondaryApp.appName)
- .dragToSplitscreen(secondaryApp.`package`, primaryApp.`package`)
+ .dragToSplitscreen(secondaryApp.packageName, primaryApp.packageName)
SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt
index 80ccaa1..394864a 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt
@@ -47,7 +47,7 @@
tapl.launchedAppState.taskbar
.openAllApps()
.getAppIcon(secondaryApp.appName)
- .dragToSplitscreen(secondaryApp.`package`, primaryApp.`package`)
+ .dragToSplitscreen(secondaryApp.packageName, primaryApp.packageName)
SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt
index a06ae6b..3b3be84 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt
@@ -53,7 +53,7 @@
.getAppIcon(secondaryApp.appName)
.openDeepShortcutMenu()
.getMenuItem("Split Screen Secondary Activity")
- .dragToSplitscreen(secondaryApp.`package`, primaryApp.`package`)
+ .dragToSplitscreen(secondaryApp.packageName, primaryApp.packageName)
SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt
index de4ec6d..eff3559 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt
@@ -46,7 +46,7 @@
transitions {
tapl.launchedAppState.taskbar
.getAppIcon(secondaryApp.appName)
- .dragToSplitscreen(secondaryApp.`package`, primaryApp.`package`)
+ .dragToSplitscreen(secondaryApp.packageName, primaryApp.packageName)
SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTest.java
index 50435a0..d098d33 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTest.java
@@ -607,4 +607,29 @@
verify(mTaskViewTaskController).applyCaptionInsetsIfNeeded();
verify(mOrganizer).applyTransaction(any());
}
+
+ @Test
+ public void testReleaseInOnTaskRemoval_noNPE() {
+ mTaskViewTaskController = spy(new TaskViewTaskController(mContext, mOrganizer,
+ mTaskViewTransitions, mSyncQueue));
+ mTaskView = new TaskView(mContext, mTaskViewTaskController);
+ mTaskView.setListener(mExecutor, new TaskView.Listener() {
+ @Override
+ public void onTaskRemovalStarted(int taskId) {
+ mTaskView.release();
+ }
+ });
+
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ mTaskViewTaskController.prepareOpenAnimation(true /* newTask */,
+ new SurfaceControl.Transaction(), new SurfaceControl.Transaction(), mTaskInfo,
+ mLeash, wct);
+ mTaskView.surfaceCreated(mock(SurfaceHolder.class));
+
+ assertThat(mTaskViewTaskController.getTaskInfo()).isEqualTo(mTaskInfo);
+
+ mTaskViewTaskController.prepareCloseAnimation();
+
+ assertThat(mTaskViewTaskController.getTaskInfo()).isNull();
+ }
}
diff --git a/media/java/android/media/AudioFocusRequest.java b/media/java/android/media/AudioFocusRequest.java
index 4c0850b..4ad3cd1 100644
--- a/media/java/android/media/AudioFocusRequest.java
+++ b/media/java/android/media/AudioFocusRequest.java
@@ -39,8 +39,8 @@
* but there is only one the user would really listen to (focus on), while the other plays in
* the background. An example of this is driving directions being spoken while music plays at
* a reduced volume (a.k.a. ducking).
- * <p>When an application requests audio focus, it expresses its intention to “own” audio focus to
- * play audio. Let’s review the different types of focus requests, the return value after a request,
+ * <p>When an application requests audio focus, it expresses its intention to "own" audio focus to
+ * play audio. Let's review the different types of focus requests, the return value after a request,
* and the responses to a loss.
* <p class="note">Note: applications should not play anything until granted focus.</p>
*
@@ -51,7 +51,7 @@
* <li>{@link AudioManager#AUDIOFOCUS_GAIN} expresses the fact that your application is now the
* sole source of audio that the user is listening to. The duration of the audio playback is
* unknown, and is possibly very long: after the user finishes interacting with your application,
- * (s)he doesn’t expect another audio stream to resume. Examples of uses of this focus gain are
+ * (s)he doesn't expect another audio stream to resume. Examples of uses of this focus gain are
* for music playback, for a game or a video player.</li>
*
* <li>{@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT} is for a situation when you know your
@@ -60,20 +60,20 @@
* for playing an alarm, or during a VoIP call. The playback is known to be finite: the alarm will
* time-out or be dismissed, the VoIP call has a beginning and an end. When any of those events
* ends, and if the user was listening to music when it started, the user expects music to resume,
- * but didn’t wish to listen to both at the same time.</li>
+ * but didn't wish to listen to both at the same time.</li>
*
* <li>{@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK}: this focus request type is similar
* to {@code AUDIOFOCUS_GAIN_TRANSIENT} for the temporary aspect of the focus request, but it also
* expresses the fact during the time you own focus, you allow another application to keep playing
- * at a reduced volume, “ducked”. Examples are when playing driving directions or notifications,
- * it’s ok for music to keep playing, but not loud enough that it would prevent the directions to
- * be hard to understand. A typical attenuation by the “ducked” application is a factor of 0.2f
+ * at a reduced volume, "ducked". Examples are when playing driving directions or notifications,
+ * it's ok for music to keep playing, but not loud enough that it would prevent the directions to
+ * be hard to understand. A typical attenuation by the "ducked" application is a factor of 0.2f
* (or -14dB), that can for instance be applied with {@code MediaPlayer.setVolume(0.2f)} when
* using this class for playback.</li>
*
* <li>{@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} is also for a temporary request,
* but also expresses that your application expects the device to not play anything else. This is
- * typically used if you are doing audio recording or speech recognition, and don’t want for
+ * typically used if you are doing audio recording or speech recognition, and don't want for
* examples notifications to be played by the system during that time.</li>
* </ul>
*
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 4323c73..1ee5aa3 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1057,7 +1057,7 @@
* this API to pass the cookies as a list of HttpCookie. If the app has not installed
* a CookieHandler already, this API creates a CookieManager and populates its CookieStore with
* the provided cookies. If the app has installed its own handler already, this API requires the
- * handler to be of CookieManager type such that the API can update the manager’s CookieStore.
+ * handler to be of CookieManager type such that the API can update the manager's CookieStore.
*
* <p><strong>Note</strong> that the cross domain redirection is allowed by default,
* but that can be changed with key/value pairs through the headers parameter with
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index 1baae4a..94a061a 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -105,27 +105,26 @@
* <p>Uses {@link MediaRoute2Info#getId()} to set each entry's key.
*/
@GuardedBy("mLock")
- final Map<String, MediaRoute2Info> mRoutes = new ArrayMap<>();
+ private final Map<String, MediaRoute2Info> mRoutes = new ArrayMap<>();
+
+ private final RoutingController mSystemController;
@GuardedBy("mLock")
- @Nullable
- private RouteListingPreference mRouteListingPreference;
+ private final Map<String, RoutingController> mNonSystemRoutingControllers = new ArrayMap<>();
- final RoutingController mSystemController;
+ private final AtomicInteger mNextRequestId = new AtomicInteger(1);
+ private final Handler mHandler;
@GuardedBy("mLock")
private RouteDiscoveryPreference mDiscoveryPreference = RouteDiscoveryPreference.EMPTY;
// TODO: Make MediaRouter2 is always connected to the MediaRouterService.
@GuardedBy("mLock")
- MediaRouter2Stub mStub;
+ private MediaRouter2Stub mStub;
@GuardedBy("mLock")
- private final Map<String, RoutingController> mNonSystemRoutingControllers = new ArrayMap<>();
-
- private final AtomicInteger mNextRequestId = new AtomicInteger(1);
-
- final Handler mHandler;
+ @Nullable
+ private RouteListingPreference mRouteListingPreference;
/**
* Stores an auxiliary copy of {@link #mFilteredRoutes} at the time of the last route callback
@@ -314,21 +313,6 @@
}
/**
- * Returns whether any route in {@code routeList} has a same unique ID with given route.
- *
- * @hide
- */
- static boolean checkRouteListContainsRouteId(
- @NonNull List<MediaRoute2Info> routeList, @NonNull String routeId) {
- for (MediaRoute2Info info : routeList) {
- if (TextUtils.equals(routeId, info.getId())) {
- return true;
- }
- }
- return false;
- }
-
- /**
* Gets the client package name of the app which this media router controls.
*
* <p>This will return null for non-system media routers.
@@ -1492,13 +1476,13 @@
}
List<MediaRoute2Info> selectedRoutes = getSelectedRoutes();
- if (checkRouteListContainsRouteId(selectedRoutes, route.getId())) {
+ if (containsRouteInfoWithId(selectedRoutes, route.getId())) {
Log.w(TAG, "Ignoring selecting a route that is already selected. route=" + route);
return;
}
List<MediaRoute2Info> selectableRoutes = getSelectableRoutes();
- if (!checkRouteListContainsRouteId(selectableRoutes, route.getId())) {
+ if (!containsRouteInfoWithId(selectableRoutes, route.getId())) {
Log.w(TAG, "Ignoring selecting a non-selectable route=" + route);
return;
}
@@ -1531,13 +1515,13 @@
}
List<MediaRoute2Info> selectedRoutes = getSelectedRoutes();
- if (!checkRouteListContainsRouteId(selectedRoutes, route.getId())) {
+ if (!containsRouteInfoWithId(selectedRoutes, route.getId())) {
Log.w(TAG, "Ignoring deselecting a route that is not selected. route=" + route);
return;
}
List<MediaRoute2Info> deselectableRoutes = getDeselectableRoutes();
- if (!checkRouteListContainsRouteId(deselectableRoutes, route.getId())) {
+ if (!containsRouteInfoWithId(deselectableRoutes, route.getId())) {
Log.w(TAG, "Ignoring deselecting a non-deselectable route=" + route);
return;
}
@@ -1700,6 +1684,16 @@
}
}
+ /** Returns whether any route in {@code routeList} has a same unique ID with given route. */
+ private static boolean containsRouteInfoWithId(
+ @NonNull List<MediaRoute2Info> routeList, @NonNull String routeId) {
+ for (MediaRoute2Info info : routeList) {
+ if (TextUtils.equals(routeId, info.getId())) {
+ return true;
+ }
+ }
+ return false;
+ }
}
class SystemRoutingController extends RoutingController {
diff --git a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java
index c8df760..864a8bb 100644
--- a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java
+++ b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java
@@ -123,7 +123,8 @@
@Override
public boolean performClick() {
- return mSwitch.performClick();
+ mSwitch.performClick();
+ return super.performClick();
}
/**
diff --git a/packages/SettingsLib/SettingsSpinner/Android.bp b/packages/SettingsLib/SettingsSpinner/Android.bp
index d3cc4d1..cbb570e 100644
--- a/packages/SettingsLib/SettingsSpinner/Android.bp
+++ b/packages/SettingsLib/SettingsSpinner/Android.bp
@@ -20,4 +20,8 @@
sdk_version: "system_current",
min_sdk_version: "21",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.healthfitness",
+ ],
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/PrimarySwitchPreference.java b/packages/SettingsLib/src/com/android/settingslib/PrimarySwitchPreference.java
index 3ec5eba..363e20aa 100644
--- a/packages/SettingsLib/src/com/android/settingslib/PrimarySwitchPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/PrimarySwitchPreference.java
@@ -133,6 +133,12 @@
}
}
+ @Override
+ public void setEnabled(boolean enabled) {
+ super.setEnabled(enabled);
+ setSwitchEnabled(enabled);
+ }
+
@VisibleForTesting(otherwise = VisibleForTesting.NONE)
public boolean isSwitchEnabled() {
return mEnableSwitch;
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
index cb8e7e8..dcb0a07 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
@@ -23,6 +23,7 @@
import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.UserHandle;
import android.text.TextUtils;
@@ -229,13 +230,15 @@
}
private void updateDisabledState() {
+ boolean isEnabled = !(mDisabledByAdmin || mDisabledByAppOps);
if (!(mPreference instanceof RestrictedTopLevelPreference)) {
- mPreference.setEnabled(!(mDisabledByAdmin || mDisabledByAppOps));
+ mPreference.setEnabled(isEnabled);
}
- if (mPreference instanceof PrimarySwitchPreference) {
- ((PrimarySwitchPreference) mPreference)
- .setSwitchEnabled(!(mDisabledByAdmin || mDisabledByAppOps));
+ Drawable icon = mPreference.getIcon();
+ if (!isEnabled && icon != null) {
+ Utils.convertToGrayscale(icon);
+ mPreference.setIcon(icon);
}
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index c967b56..9d533fa 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -700,4 +700,14 @@
return false;
}
+ /**
+ * Convert a drawable to grayscale drawable
+ */
+ public static void convertToGrayscale(@NonNull Drawable drawable) {
+ ColorMatrix matrix = new ColorMatrix();
+ matrix.setSaturation(0.0f);
+
+ ColorMatrixColorFilter filter = new ColorMatrixColorFilter(matrix);
+ drawable.setColorFilter(filter);
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
index a05a6e9..69b61c7 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
@@ -25,10 +25,13 @@
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothLeAudioContentMetadata;
import android.bluetooth.BluetoothLeBroadcast;
+import android.bluetooth.BluetoothLeBroadcastAssistant;
import android.bluetooth.BluetoothLeBroadcastMetadata;
+import android.bluetooth.BluetoothLeBroadcastReceiveState;
import android.bluetooth.BluetoothLeBroadcastSubgroup;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothProfile.ServiceListener;
+import android.bluetooth.BluetoothStatusCodes;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
@@ -39,6 +42,7 @@
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
+import android.util.Pair;
import androidx.annotation.RequiresApi;
@@ -76,14 +80,16 @@
Settings.Secure.getUriFor(Settings.Secure.BLUETOOTH_LE_BROADCAST_APP_SOURCE_NAME),
};
- private BluetoothLeBroadcast mService;
+ private BluetoothLeBroadcast mServiceBroadcast;
+ private BluetoothLeBroadcastAssistant mServiceBroadcastAssistant;
private BluetoothLeAudioContentMetadata mBluetoothLeAudioContentMetadata;
private BluetoothLeBroadcastMetadata mBluetoothLeBroadcastMetadata;
private BluetoothLeAudioContentMetadata.Builder mBuilder;
private int mBroadcastId = UNKNOWN_VALUE_PLACEHOLDER;
private String mAppSourceName = "";
private String mNewAppSourceName = "";
- private boolean mIsProfileReady;
+ private boolean mIsBroadcastProfileReady = false;
+ private boolean mIsBroadcastAssistantProfileReady = false;
private String mProgramInfo;
private byte[] mBroadcastCode;
private Executor mExecutor;
@@ -94,17 +100,22 @@
@Override
public void onServiceConnected(int profile, BluetoothProfile proxy) {
if (DEBUG) {
- Log.d(TAG, "Bluetooth service connected");
+ Log.d(TAG, "Bluetooth service connected: " + profile);
}
- if(!mIsProfileReady) {
- mService = (BluetoothLeBroadcast) proxy;
- mIsProfileReady = true;
+ if ((profile == BluetoothProfile.LE_AUDIO_BROADCAST) && !mIsBroadcastProfileReady) {
+ mServiceBroadcast = (BluetoothLeBroadcast) proxy;
+ mIsBroadcastProfileReady = true;
registerServiceCallBack(mExecutor, mBroadcastCallback);
List<BluetoothLeBroadcastMetadata> metadata = getAllBroadcastMetadata();
if (!metadata.isEmpty()) {
updateBroadcastInfoFromBroadcastMetadata(metadata.get(0));
}
registerContentObserver();
+ } else if ((profile == BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT)
+ && !mIsBroadcastAssistantProfileReady) {
+ mIsBroadcastAssistantProfileReady = true;
+ mServiceBroadcastAssistant = (BluetoothLeBroadcastAssistant) proxy;
+ registerBroadcastAssistantCallback(mExecutor, mBroadcastAssistantCallback);
}
}
@@ -113,9 +124,17 @@
if (DEBUG) {
Log.d(TAG, "Bluetooth service disconnected");
}
- if(mIsProfileReady) {
- mIsProfileReady = false;
+ if ((profile == BluetoothProfile.LE_AUDIO_BROADCAST) && mIsBroadcastProfileReady) {
+ mIsBroadcastProfileReady = false;
unregisterServiceCallBack(mBroadcastCallback);
+ }
+ if ((profile == BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT)
+ && mIsBroadcastAssistantProfileReady) {
+ mIsBroadcastAssistantProfileReady = false;
+ unregisterBroadcastAssistantCallback(mBroadcastAssistantCallback);
+ }
+
+ if (!mIsBroadcastAssistantProfileReady && !mIsBroadcastProfileReady) {
unregisterContentObserver();
}
}
@@ -157,6 +176,8 @@
"onBroadcastStopped(), reason = " + reason + ", broadcastId = "
+ broadcastId);
}
+
+ stopLocalSourceReceivers();
resetCacheInfo();
}
@@ -196,6 +217,61 @@
}
};
+ private final BluetoothLeBroadcastAssistant.Callback mBroadcastAssistantCallback =
+ new BluetoothLeBroadcastAssistant.Callback() {
+ @Override
+ public void onSourceAdded(@NonNull BluetoothDevice sink, int sourceId,
+ int reason) {}
+ @Override
+ public void onSearchStarted(int reason) {}
+
+ @Override
+ public void onSearchStartFailed(int reason) {}
+
+ @Override
+ public void onSearchStopped(int reason) {}
+
+ @Override
+ public void onSearchStopFailed(int reason) {}
+
+ @Override
+ public void onSourceFound(@NonNull BluetoothLeBroadcastMetadata source) {}
+
+ @Override
+ public void onSourceAddFailed(@NonNull BluetoothDevice sink,
+ @NonNull BluetoothLeBroadcastMetadata source, int reason) {}
+
+ @Override
+ public void onSourceModified(@NonNull BluetoothDevice sink, int sourceId,
+ int reason) {}
+
+ @Override
+ public void onSourceModifyFailed(@NonNull BluetoothDevice sink, int sourceId,
+ int reason) {}
+
+ @Override
+ public void onSourceRemoved(@NonNull BluetoothDevice sink, int sourceId,
+ int reason) {
+ if (DEBUG) {
+ Log.d(TAG, "onSourceRemoved(), sink = " + sink + ", reason = "
+ + reason + ", sourceId = " + sourceId);
+ }
+ }
+
+ @Override
+ public void onSourceRemoveFailed(@NonNull BluetoothDevice sink, int sourceId,
+ int reason) {
+ if (DEBUG) {
+ Log.d(TAG, "onSourceRemoveFailed(), sink = " + sink + ", reason = "
+ + reason + ", sourceId = " + sourceId);
+ }
+ }
+
+ @Override
+ public void onReceiveStateChanged(@NonNull BluetoothDevice sink, int sourceId,
+ @NonNull BluetoothLeBroadcastReceiveState state) {}
+ };
+
private class BroadcastSettingsObserver extends ContentObserver {
BroadcastSettingsObserver(Handler h) {
super(h);
@@ -219,6 +295,9 @@
// Before registering callback, the constructor should finish creating the all of variables.
BluetoothAdapter.getDefaultAdapter()
.getProfileProxy(context, mServiceListener, BluetoothProfile.LE_AUDIO_BROADCAST);
+ BluetoothAdapter.getDefaultAdapter()
+ .getProfileProxy(context, mServiceListener,
+ BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
}
/**
@@ -227,7 +306,7 @@
*/
public void startBroadcast(String appSourceName, String language) {
mNewAppSourceName = appSourceName;
- if (mService == null) {
+ if (mServiceBroadcast == null) {
Log.d(TAG, "The BluetoothLeBroadcast is null when starting the broadcast.");
return;
}
@@ -237,7 +316,7 @@
"startBroadcast: language = " + language + " ,programInfo = " + programInfo);
}
buildContentMetadata(language, programInfo);
- mService.startBroadcast(mBluetoothLeAudioContentMetadata,
+ mServiceBroadcast.startBroadcast(mBluetoothLeAudioContentMetadata,
(mBroadcastCode != null && mBroadcastCode.length > 0) ? mBroadcastCode : null);
}
@@ -341,13 +420,13 @@
}
public BluetoothLeBroadcastMetadata getLatestBluetoothLeBroadcastMetadata() {
- if (mService == null) {
+ if (mServiceBroadcast == null) {
Log.d(TAG, "The BluetoothLeBroadcast is null");
return null;
}
if (mBluetoothLeBroadcastMetadata == null) {
final List<BluetoothLeBroadcastMetadata> metadataList =
- mService.getAllBroadcastMetadata();
+ mServiceBroadcast.getAllBroadcastMetadata();
mBluetoothLeBroadcastMetadata = metadataList.stream()
.filter(i -> i.getBroadcastId() == mBroadcastId)
.findFirst()
@@ -411,14 +490,14 @@
* corresponding callback {@link BluetoothLeBroadcast.Callback}.
*/
public void stopBroadcast(int broadcastId) {
- if (mService == null) {
+ if (mServiceBroadcast == null) {
Log.d(TAG, "The BluetoothLeBroadcast is null when stopping the broadcast.");
return;
}
if (DEBUG) {
Log.d(TAG, "stopBroadcast()");
}
- mService.stopBroadcast(broadcastId);
+ mServiceBroadcast.stopBroadcast(broadcastId);
}
/**
@@ -426,7 +505,7 @@
* corresponding callback {@link BluetoothLeBroadcast.Callback}.
*/
public void updateBroadcast(String appSourceName, String language) {
- if (mService == null) {
+ if (mServiceBroadcast == null) {
Log.d(TAG, "The BluetoothLeBroadcast is null when updating the broadcast.");
return;
}
@@ -437,26 +516,57 @@
}
mNewAppSourceName = appSourceName;
mBluetoothLeAudioContentMetadata = mBuilder.setProgramInfo(programInfo).build();
- mService.updateBroadcast(mBroadcastId, mBluetoothLeAudioContentMetadata);
+ mServiceBroadcast.updateBroadcast(mBroadcastId, mBluetoothLeAudioContentMetadata);
}
public void registerServiceCallBack(@NonNull @CallbackExecutor Executor executor,
@NonNull BluetoothLeBroadcast.Callback callback) {
- if (mService == null) {
+ if (mServiceBroadcast == null) {
Log.d(TAG, "The BluetoothLeBroadcast is null.");
return;
}
- mService.registerCallback(executor, callback);
+ mServiceBroadcast.registerCallback(executor, callback);
+ }
+
+ /**
+ * Register Broadcast Assistant Callbacks to track it's state and receivers
+ *
+ * @param executor Executor object for callback
+ * @param callback Callback object to be registered
+ */
+ public void registerBroadcastAssistantCallback(@NonNull @CallbackExecutor Executor executor,
+ @NonNull BluetoothLeBroadcastAssistant.Callback callback) {
+ if (mServiceBroadcastAssistant == null) {
+ Log.d(TAG, "The BluetoothLeBroadcastAssisntant is null.");
+ return;
+ }
+
+ mServiceBroadcastAssistant.registerCallback(executor, callback);
}
public void unregisterServiceCallBack(@NonNull BluetoothLeBroadcast.Callback callback) {
- if (mService == null) {
+ if (mServiceBroadcast == null) {
Log.d(TAG, "The BluetoothLeBroadcast is null.");
return;
}
- mService.unregisterCallback(callback);
+ mServiceBroadcast.unregisterCallback(callback);
+ }
+
+ /**
+ * Unregister previousely registered Broadcast Assistant Callbacks
+ *
+ * @param callback Callback object to be unregistered
+ */
+ public void unregisterBroadcastAssistantCallback(
+ @NonNull BluetoothLeBroadcastAssistant.Callback callback) {
+ if (mServiceBroadcastAssistant == null) {
+ Log.d(TAG, "The BluetoothLeBroadcastAssisntant is null.");
+ return;
+ }
+
+ mServiceBroadcastAssistant.unregisterCallback(callback);
}
private void buildContentMetadata(String language, String programInfo) {
@@ -474,7 +584,7 @@
}
public boolean isProfileReady() {
- return mIsProfileReady;
+ return mIsBroadcastProfileReady;
}
@Override
@@ -494,40 +604,40 @@
* Not supported since LE Audio Broadcasts do not establish a connection.
*/
public int getConnectionStatus(BluetoothDevice device) {
- if (mService == null) {
+ if (mServiceBroadcast == null) {
return BluetoothProfile.STATE_DISCONNECTED;
}
// LE Audio Broadcasts are not connection-oriented.
- return mService.getConnectionState(device);
+ return mServiceBroadcast.getConnectionState(device);
}
/**
* Not supported since LE Audio Broadcasts do not establish a connection.
*/
public List<BluetoothDevice> getConnectedDevices() {
- if (mService == null) {
+ if (mServiceBroadcast == null) {
return new ArrayList<BluetoothDevice>(0);
}
// LE Audio Broadcasts are not connection-oriented.
- return mService.getConnectedDevices();
+ return mServiceBroadcast.getConnectedDevices();
}
public @NonNull
List<BluetoothLeBroadcastMetadata> getAllBroadcastMetadata() {
- if (mService == null) {
+ if (mServiceBroadcast == null) {
Log.d(TAG, "The BluetoothLeBroadcast is null.");
return Collections.emptyList();
}
- return mService.getAllBroadcastMetadata();
+ return mServiceBroadcast.getAllBroadcastMetadata();
}
public boolean isEnabled(BluetoothDevice device) {
- if (mService == null) {
+ if (mServiceBroadcast == null) {
return false;
}
- return !mService.getAllBroadcastMetadata().isEmpty();
+ return !mServiceBroadcast.getAllBroadcastMetadata().isEmpty();
}
/**
@@ -571,12 +681,12 @@
if (DEBUG) {
Log.d(TAG, "finalize()");
}
- if (mService != null) {
+ if (mServiceBroadcast != null) {
try {
BluetoothAdapter.getDefaultAdapter().closeProfileProxy(
BluetoothProfile.LE_AUDIO_BROADCAST,
- mService);
- mService = null;
+ mServiceBroadcast);
+ mServiceBroadcast = null;
} catch (Throwable t) {
Log.w(TAG, "Error cleaning up LeAudio proxy", t);
}
@@ -626,4 +736,21 @@
}
mContentResolver.unregisterContentObserver(mSettingsObserver);
}
+
+ private void stopLocalSourceReceivers() {
+ if (DEBUG) {
+ Log.d(TAG, "stopLocalSourceReceivers()");
+ }
+ for (BluetoothDevice device : mServiceBroadcastAssistant.getConnectedDevices()) {
+ for (BluetoothLeBroadcastReceiveState receiveState :
+ mServiceBroadcastAssistant.getAllSources(device)) {
+ /* Check if local/last broadcast is the synced one */
+ int localBroadcastId = getLatestBroadcastId();
+ if (receiveState.getBroadcastId() != localBroadcastId) continue;
+
+ mServiceBroadcastAssistant.removeSource(device, receiveState.getSourceId());
+ }
+ }
+ }
+
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index d1d745f..7e97956 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -1997,7 +1997,7 @@
case MUTATION_OPERATION_RESET: {
mSettingsRegistry.resetSettingsLocked(SETTINGS_TYPE_SYSTEM,
- UserHandle.USER_SYSTEM, callingPackage, mode, tag);
+ runAsUserId, callingPackage, mode, tag);
return true;
}
}
@@ -3254,6 +3254,15 @@
return settingsState.getSettingLocked(name);
}
+ private static boolean shouldExcludeSettingFromReset(Setting setting, String prefix) {
+ // If a prefix was specified, exclude settings whose names don't start with it.
+ if (prefix != null && !setting.getName().startsWith(prefix)) {
+ return true;
+ }
+ // Never reset SECURE_FRP_MODE, as it could be abused to bypass FRP via RescueParty.
+ return Global.SECURE_FRP_MODE.equals(setting.getName());
+ }
+
public void resetSettingsLocked(int type, int userId, String packageName, int mode,
String tag) {
resetSettingsLocked(type, userId, packageName, mode, tag, /*prefix=*/
@@ -3276,7 +3285,7 @@
Setting setting = settingsState.getSettingLocked(name);
if (packageName.equals(setting.getPackageName())) {
if ((tag != null && !tag.equals(setting.getTag()))
- || (prefix != null && !setting.getName().startsWith(prefix))) {
+ || shouldExcludeSettingFromReset(setting, prefix)) {
continue;
}
if (settingsState.resetSettingLocked(name)) {
@@ -3297,7 +3306,7 @@
Setting setting = settingsState.getSettingLocked(name);
if (!SettingsState.isSystemPackage(getContext(),
setting.getPackageName())) {
- if (prefix != null && !setting.getName().startsWith(prefix)) {
+ if (shouldExcludeSettingFromReset(setting, prefix)) {
continue;
}
if (settingsState.resetSettingLocked(name)) {
@@ -3318,7 +3327,7 @@
Setting setting = settingsState.getSettingLocked(name);
if (!SettingsState.isSystemPackage(getContext(),
setting.getPackageName())) {
- if (prefix != null && !setting.getName().startsWith(prefix)) {
+ if (shouldExcludeSettingFromReset(setting, prefix)) {
continue;
}
if (setting.isDefaultFromSystem()) {
@@ -3343,7 +3352,7 @@
for (String name : settingsState.getSettingNamesLocked()) {
Setting setting = settingsState.getSettingLocked(name);
boolean someSettingChanged = false;
- if (prefix != null && !setting.getName().startsWith(prefix)) {
+ if (shouldExcludeSettingFromReset(setting, prefix)) {
continue;
}
if (setting.isDefaultFromSystem()) {
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java
index eaf0dcb..a945c33 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java
@@ -464,6 +464,31 @@
}
}
+ // To prevent FRP bypasses, the SECURE_FRP_MODE setting should not be reset when all other
+ // settings are reset. But it should still be possible to explicitly set its value.
+ @Test
+ public void testSecureFrpModeSettingCannotBeReset() throws Exception {
+ final String name = Settings.Global.SECURE_FRP_MODE;
+ final String origValue = getSetting(SETTING_TYPE_GLOBAL, name);
+ setSettingViaShell(SETTING_TYPE_GLOBAL, name, "1", false);
+ try {
+ assertEquals("1", getSetting(SETTING_TYPE_GLOBAL, name));
+ for (int type : new int[] { SETTING_TYPE_GLOBAL, SETTING_TYPE_SECURE }) {
+ resetSettingsViaShell(type, Settings.RESET_MODE_UNTRUSTED_DEFAULTS);
+ resetSettingsViaShell(type, Settings.RESET_MODE_UNTRUSTED_CHANGES);
+ resetSettingsViaShell(type, Settings.RESET_MODE_TRUSTED_DEFAULTS);
+ }
+ // The value should still be "1". It should not have been reset to null.
+ assertEquals("1", getSetting(SETTING_TYPE_GLOBAL, name));
+ // It should still be possible to explicitly set the value to "0".
+ setSettingViaShell(SETTING_TYPE_GLOBAL, name, "0", false);
+ assertEquals("0", getSetting(SETTING_TYPE_GLOBAL, name));
+ } finally {
+ setSettingViaShell(SETTING_TYPE_GLOBAL, name, origValue, false);
+ assertEquals(origValue, getSetting(SETTING_TYPE_GLOBAL, name));
+ }
+ }
+
private void doTestQueryStringInBracketsViaProviderApiForType(int type) {
// Make sure we have a clean slate.
deleteStringViaProviderApi(type, FAKE_SETTING_NAME);
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/layout/grid_item.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/layout/grid_item.xml
index a902c5b..587395d 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/layout/grid_item.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/layout/grid_item.xml
@@ -13,7 +13,7 @@
android:layout_height="@dimen/image_button_height"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
- android:scaleType="fitCenter"></ImageButton>
+ android:scaleType="fitCenter"/>
<TextView
android:id="@+id/shortcutLabel"
@@ -22,7 +22,6 @@
android:layout_marginTop="@dimen/grid_item_text_view_margin_top"
android:layout_below="@+id/shortcutIconBtn"
android:layout_centerHorizontal="true"
- android:ellipsize="end"
android:gravity="center_horizontal"
android:importantForAccessibility="no"
android:lines="2"
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
index 6d9497d..b9baa793 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
@@ -46,6 +46,7 @@
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
+import com.android.compose.animation.scene.SceneScope
import com.android.systemui.R
import com.android.systemui.bouncer.ui.viewmodel.AuthMethodBouncerViewModel
import com.android.systemui.bouncer.ui.viewmodel.BouncerViewModel
@@ -81,7 +82,7 @@
.asStateFlow()
@Composable
- override fun Content(
+ override fun SceneScope.Content(
modifier: Modifier,
) = BouncerScene(viewModel, dialogFactory, modifier)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt
index ab7bc26..ca7352e 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt
@@ -29,6 +29,7 @@
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
+import com.android.compose.animation.scene.SceneScope
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.common.ui.compose.Icon
import com.android.systemui.dagger.SysUISingleton
@@ -66,7 +67,7 @@
)
@Composable
- override fun Content(
+ override fun SceneScope.Content(
modifier: Modifier,
) {
LockscreenScene(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
index 130395a..29763c2 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
@@ -27,6 +27,7 @@
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
+import com.android.compose.animation.scene.SceneScope
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.qs.ui.viewmodel.QuickSettingsSceneViewModel
import com.android.systemui.scene.shared.model.Direction
@@ -57,7 +58,7 @@
.asStateFlow()
@Composable
- override fun Content(
+ override fun SceneScope.Content(
modifier: Modifier,
) {
QuickSettingsScene(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/ComposableScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/ComposableScene.kt
index a213666..3da6a02 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/ComposableScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/ComposableScene.kt
@@ -18,9 +18,10 @@
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
+import com.android.compose.animation.scene.SceneScope
import com.android.systemui.scene.shared.model.Scene
/** Compose-capable extension of [Scene]. */
interface ComposableScene : Scene {
- @Composable fun Content(modifier: Modifier)
+ @Composable fun SceneScope.Content(modifier: Modifier)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt
index 0070552..774c409 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt
@@ -23,6 +23,7 @@
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import com.android.compose.animation.scene.SceneScope
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.scene.shared.model.Direction
import com.android.systemui.scene.shared.model.SceneKey
@@ -50,7 +51,7 @@
.asStateFlow()
@Composable
- override fun Content(
+ override fun SceneScope.Content(
modifier: Modifier,
) {
/*
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
index 49e2bf9..3dfdbba 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
@@ -14,32 +14,31 @@
* limitations under the License.
*/
-@file:OptIn(ExperimentalAnimationApi::class)
-
package com.android.systemui.scene.ui.composable
-import androidx.activity.compose.BackHandler
-import androidx.compose.animation.AnimatedContent
-import androidx.compose.animation.ExperimentalAnimationApi
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.material3.Button
-import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
-import androidx.compose.ui.Alignment
+import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
-import androidx.compose.ui.unit.dp
+import com.android.compose.animation.scene.Back
+import com.android.compose.animation.scene.ObservableTransitionState as SceneTransitionObservableTransitionState
+import com.android.compose.animation.scene.SceneKey as SceneTransitionSceneKey
+import com.android.compose.animation.scene.SceneTransitionLayout
+import com.android.compose.animation.scene.SceneTransitionLayoutState
+import com.android.compose.animation.scene.Swipe
+import com.android.compose.animation.scene.UserAction as SceneTransitionUserAction
+import com.android.compose.animation.scene.observableTransitionState
+import com.android.compose.animation.scene.transitions
import com.android.systemui.scene.shared.model.Direction
+import com.android.systemui.scene.shared.model.ObservableTransitionState
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import com.android.systemui.scene.shared.model.UserAction
import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModel
-import java.util.Locale
+import kotlinx.coroutines.flow.map
/**
* Renders a container of a collection of "scenes" that the user can switch between using certain
@@ -64,77 +63,94 @@
sceneByKey: Map<SceneKey, ComposableScene>,
modifier: Modifier = Modifier,
) {
- val currentScene: SceneModel by viewModel.currentScene.collectAsState()
+ val currentSceneModel: SceneModel by viewModel.currentScene.collectAsState()
+ val currentSceneKey = currentSceneModel.key
+ val currentScene = checkNotNull(sceneByKey[currentSceneKey])
+ val currentDestinations: Map<UserAction, SceneModel> by
+ currentScene.destinationScenes().collectAsState()
+ val state = remember { SceneTransitionLayoutState(currentSceneKey.toTransitionSceneKey()) }
- AnimatedContent(
- targetState = currentScene.key,
- label = "scene container",
- modifier = modifier,
- ) { currentSceneKey ->
- sceneByKey.forEach { (key, composableScene) ->
- if (key == currentSceneKey) {
- Scene(
- scene = composableScene,
- onSceneChanged = viewModel::setCurrentScene,
- modifier = Modifier.fillMaxSize(),
- )
- }
- }
+ DisposableEffect(viewModel, state) {
+ viewModel.setTransitionState(state.observableTransitionState().map { it.toModel() })
+ onDispose { viewModel.setTransitionState(null) }
}
-}
-/** Renders the given [ComposableScene]. */
-@Composable
-private fun Scene(
- scene: ComposableScene,
- onSceneChanged: (SceneModel) -> Unit,
- modifier: Modifier = Modifier,
-) {
- val destinationScenes: Map<UserAction, SceneModel> by scene.destinationScenes().collectAsState()
- val swipeLeftDestinationScene = destinationScenes[UserAction.Swipe(Direction.LEFT)]
- val swipeUpDestinationScene = destinationScenes[UserAction.Swipe(Direction.UP)]
- val swipeRightDestinationScene = destinationScenes[UserAction.Swipe(Direction.RIGHT)]
- val swipeDownDestinationScene = destinationScenes[UserAction.Swipe(Direction.DOWN)]
- val backDestinationScene = destinationScenes[UserAction.Back]
-
- // TODO(b/280880714): replace with the real UI and make sure to call onTransitionProgress.
- Box(modifier) {
- Column(
- horizontalAlignment = Alignment.CenterHorizontally,
- modifier = Modifier.align(Alignment.Center),
- ) {
- scene.Content(
- modifier = Modifier,
- )
-
- Row(
- horizontalArrangement = Arrangement.spacedBy(8.dp),
- ) {
- DirectionalButton(Direction.LEFT, swipeLeftDestinationScene, onSceneChanged)
- DirectionalButton(Direction.UP, swipeUpDestinationScene, onSceneChanged)
- DirectionalButton(Direction.RIGHT, swipeRightDestinationScene, onSceneChanged)
- DirectionalButton(Direction.DOWN, swipeDownDestinationScene, onSceneChanged)
- }
-
- if (backDestinationScene != null) {
- BackHandler { onSceneChanged.invoke(backDestinationScene) }
- }
- }
- }
-}
-
-@Composable
-private fun DirectionalButton(
- direction: Direction,
- destinationScene: SceneModel?,
- onSceneChanged: (SceneModel) -> Unit,
- modifier: Modifier = Modifier,
-) {
- Button(
- onClick = { destinationScene?.let { onSceneChanged.invoke(it) } },
- enabled = destinationScene != null,
- modifier = modifier,
+ SceneTransitionLayout(
+ currentScene = currentSceneKey.toTransitionSceneKey(),
+ onChangeScene = { sceneKey -> viewModel.setCurrentScene(sceneKey.toModel()) },
+ transitions = transitions {},
+ state = state,
+ modifier = modifier.fillMaxSize(),
) {
- Text(direction.name.lowercase(Locale.getDefault()))
+ sceneByKey.forEach { (sceneKey, composableScene) ->
+ scene(
+ key = sceneKey.toTransitionSceneKey(),
+ userActions =
+ if (sceneKey == currentSceneKey) {
+ currentDestinations
+ } else {
+ composableScene.destinationScenes().value
+ }
+ .map { (userAction, destinationSceneModel) ->
+ toTransitionModels(userAction, destinationSceneModel)
+ }
+ .toMap(),
+ ) {
+ with(composableScene) {
+ this@scene.Content(
+ modifier = Modifier.fillMaxSize(),
+ )
+ }
+ }
+ }
+ }
+}
+
+// TODO(b/293899074): remove this once we can use the one from SceneTransitionLayout.
+private fun SceneTransitionObservableTransitionState.toModel(): ObservableTransitionState {
+ return when (this) {
+ is SceneTransitionObservableTransitionState.Idle ->
+ ObservableTransitionState.Idle(scene.toModel().key)
+ is SceneTransitionObservableTransitionState.Transition ->
+ ObservableTransitionState.Transition(
+ fromScene = fromScene.toModel().key,
+ toScene = toScene.toModel().key,
+ progress = progress,
+ )
+ }
+}
+
+// TODO(b/293899074): remove this once we can use the one from SceneTransitionLayout.
+private fun toTransitionModels(
+ userAction: UserAction,
+ sceneModel: SceneModel,
+): Pair<SceneTransitionUserAction, SceneTransitionSceneKey> {
+ return userAction.toTransitionUserAction() to sceneModel.key.toTransitionSceneKey()
+}
+
+// TODO(b/293899074): remove this once we can use the one from SceneTransitionLayout.
+private fun SceneKey.toTransitionSceneKey(): SceneTransitionSceneKey {
+ return SceneTransitionSceneKey(
+ name = toString(),
+ identity = this,
+ )
+}
+
+// TODO(b/293899074): remove this once we can use the one from SceneTransitionLayout.
+private fun SceneTransitionSceneKey.toModel(): SceneModel {
+ return SceneModel(key = identity as SceneKey)
+}
+
+// TODO(b/293899074): remove this once we can use the one from SceneTransitionLayout.
+private fun UserAction.toTransitionUserAction(): SceneTransitionUserAction {
+ return when (this) {
+ is UserAction.Swipe ->
+ when (this.direction) {
+ Direction.LEFT -> Swipe.Left
+ Direction.UP -> Swipe.Up
+ Direction.RIGHT -> Swipe.Right
+ Direction.DOWN -> Swipe.Down
+ }
+ is UserAction.Back -> Back
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
index b73e0b2..ff1cb5f 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
@@ -26,6 +26,7 @@
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
+import com.android.compose.animation.scene.SceneScope
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.notifications.ui.composable.Notifications
@@ -63,7 +64,7 @@
)
@Composable
- override fun Content(
+ override fun SceneScope.Content(
modifier: Modifier,
) = ShadeScene(viewModel, modifier)
@@ -86,11 +87,12 @@
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(16.dp),
modifier =
- Modifier.fillMaxSize()
+ modifier
+ .fillMaxSize()
.clickable(onClick = { viewModel.onContentClicked() })
.padding(horizontal = 16.dp, vertical = 48.dp)
) {
- QuickSettings(modifier = modifier.height(160.dp))
- Notifications(modifier = modifier.weight(1f))
+ QuickSettings(modifier = Modifier.height(160.dp))
+ Notifications(modifier = Modifier.weight(1f))
}
}
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index badad58..28b5870 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -192,7 +192,7 @@
<string name="kg_prompt_after_user_lockdown_pattern">Pattern is required after lockdown</string>
<!-- Message shown to prepare for an unattended update (OTA). Also known as an over-the-air (OTA) update. [CHAR LIMIT=70] -->
- <string name="kg_prompt_unattended_update">Update will install during inactive hours</string>
+ <string name="kg_prompt_unattended_update">Update will install when device not in use</string>
<!-- Message shown when primary authentication hasn't been used for some time. [CHAR LIMIT=70] -->
<string name="kg_prompt_pin_auth_timeout">Added security required. PIN not used for a while.</string>
diff --git a/packages/SystemUI/res/layout/biometric_prompt_layout.xml b/packages/SystemUI/res/layout/biometric_prompt_layout.xml
index ecb0bfa..bea0e13 100644
--- a/packages/SystemUI/res/layout/biometric_prompt_layout.xml
+++ b/packages/SystemUI/res/layout/biometric_prompt_layout.xml
@@ -28,7 +28,6 @@
android:singleLine="true"
android:marqueeRepeatLimit="1"
android:ellipsize="marquee"
- android:importantForAccessibility="no"
style="@style/TextAppearance.AuthCredential.Title"/>
<TextView
@@ -39,7 +38,6 @@
android:singleLine="true"
android:marqueeRepeatLimit="1"
android:ellipsize="marquee"
- android:importantForAccessibility="no"
style="@style/TextAppearance.AuthCredential.Subtitle"/>
<TextView
diff --git a/packages/SystemUI/res/layout/dream_overlay_complication_clock_time.xml b/packages/SystemUI/res/layout/dream_overlay_complication_clock_time.xml
index 8bff1a1..6de10b4 100644
--- a/packages/SystemUI/res/layout/dream_overlay_complication_clock_time.xml
+++ b/packages/SystemUI/res/layout/dream_overlay_complication_clock_time.xml
@@ -14,34 +14,27 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<FrameLayout
+<com.android.systemui.shared.shadow.DoubleShadowTextClock
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
- android:layout_height="wrap_content">
-
- <com.android.systemui.shared.shadow.DoubleShadowTextClock
- android:id="@+id/time_view"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:fontFamily="@*android:string/config_clockFontFamily"
- android:textColor="@android:color/white"
- android:format12Hour="@string/dream_time_complication_12_hr_time_format"
- android:format24Hour="@string/dream_time_complication_24_hr_time_format"
- android:fontFeatureSettings="pnum, lnum"
- android:includeFontPadding="false"
- android:letterSpacing="0.02"
- android:maxLines="1"
- android:textSize="@dimen/dream_overlay_complication_clock_time_text_size"
- app:keyShadowBlur="@dimen/dream_overlay_clock_key_text_shadow_radius"
- app:keyShadowOffsetX="@dimen/dream_overlay_clock_key_text_shadow_dx"
- app:keyShadowOffsetY="@dimen/dream_overlay_clock_key_text_shadow_dy"
- app:keyShadowAlpha="0.3"
- app:ambientShadowBlur="@dimen/dream_overlay_clock_ambient_text_shadow_radius"
- app:ambientShadowOffsetX="@dimen/dream_overlay_clock_ambient_text_shadow_dx"
- app:ambientShadowOffsetY="@dimen/dream_overlay_clock_ambient_text_shadow_dy"
- app:ambientShadowAlpha="0.3"
- app:removeTextDescent="true"
- app:textDescentExtraPadding="@dimen/dream_overlay_clock_text_descent_extra_padding" />
-
-</FrameLayout>
+ android:layout_height="wrap_content"
+ android:fontFamily="@*android:string/config_clockFontFamily"
+ android:textColor="@android:color/white"
+ android:format12Hour="@string/dream_time_complication_12_hr_time_format"
+ android:format24Hour="@string/dream_time_complication_24_hr_time_format"
+ android:fontFeatureSettings="pnum, lnum"
+ android:includeFontPadding="false"
+ android:letterSpacing="0.02"
+ android:maxLines="1"
+ android:textSize="@dimen/dream_overlay_complication_clock_time_text_size"
+ app:keyShadowBlur="@dimen/dream_overlay_clock_key_text_shadow_radius"
+ app:keyShadowOffsetX="@dimen/dream_overlay_clock_key_text_shadow_dx"
+ app:keyShadowOffsetY="@dimen/dream_overlay_clock_key_text_shadow_dy"
+ app:keyShadowAlpha="0.3"
+ app:ambientShadowBlur="@dimen/dream_overlay_clock_ambient_text_shadow_radius"
+ app:ambientShadowOffsetX="@dimen/dream_overlay_clock_ambient_text_shadow_dx"
+ app:ambientShadowOffsetY="@dimen/dream_overlay_clock_ambient_text_shadow_dy"
+ app:ambientShadowAlpha="0.3"
+ app:removeTextDescent="true"
+ app:textDescentExtraPadding="@dimen/dream_overlay_clock_text_descent_extra_padding" />
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
index bb11217..b81e081 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
@@ -178,6 +178,7 @@
getKeyguardSecurityCallback().dismiss(true, userId, getSecurityMode());
}
} else {
+ mView.resetPasswordText(true /* animate */, false /* announce deletion if no match */);
if (isValidPassword) {
getKeyguardSecurityCallback().reportUnlockAttempt(userId, false, timeoutMs);
if (timeoutMs > 0) {
@@ -186,7 +187,6 @@
handleAttemptLockout(deadline);
}
}
- mView.resetPasswordText(true /* animate */, false /* announce deletion if no match */);
if (timeoutMs == 0) {
mMessageAreaController.setMessage(mView.getWrongPasswordStringId());
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index 3b09910f..aff2591 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -27,6 +27,7 @@
import static com.android.keyguard.KeyguardSecurityContainer.USER_TYPE_SECONDARY_USER;
import static com.android.keyguard.KeyguardSecurityContainer.USER_TYPE_WORK_PROFILE;
import static com.android.systemui.DejankUtils.whitelistIpcs;
+import static com.android.systemui.flags.Flags.REVAMPED_BOUNCER_MESSAGES;
import android.app.ActivityManager;
import android.app.admin.DevicePolicyManager;
@@ -1081,8 +1082,10 @@
mLockPatternUtils.reportFailedPasswordAttempt(userId);
if (timeoutMs > 0) {
mLockPatternUtils.reportPasswordLockout(timeoutMs, userId);
- mView.showTimeoutDialog(userId, timeoutMs, mLockPatternUtils,
- mSecurityModel.getSecurityMode(userId));
+ if (!mFeatureFlags.isEnabled(REVAMPED_BOUNCER_MESSAGES)) {
+ mView.showTimeoutDialog(userId, timeoutMs, mLockPatternUtils,
+ mSecurityModel.getSecurityMode(userId));
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 48442a5..c03053d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -2696,14 +2696,6 @@
}
/**
- * @return true if the FP sensor is non-UDFPS and the device can be unlocked using fingerprint
- * at this moment.
- */
- public boolean isFingerprintAllowedInBouncer() {
- return !isUdfpsSupported() && isUnlockingWithFingerprintAllowed();
- }
-
- /**
* @return true if there's at least one sfps enrollment for the current user.
*/
public boolean isSfpsEnrolled() {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricNotificationService.java b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricNotificationService.java
index 4b17be3..dc874d8 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricNotificationService.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricNotificationService.java
@@ -135,6 +135,9 @@
intentFilter.addAction(ACTION_SHOW_FACE_REENROLL_DIALOG);
mContext.registerReceiver(mBroadcastReceiver, intentFilter,
Context.RECEIVER_EXPORTED_UNAUDITED);
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.FACE_UNLOCK_RE_ENROLL, REENROLL_NOT_REQUIRED,
+ UserHandle.USER_CURRENT);
}
private void queueFaceReenrollNotification() {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/LogContextInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/LogContextInteractor.kt
index 86940ca..863ba8d 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/LogContextInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/LogContextInteractor.kt
@@ -82,7 +82,9 @@
) : LogContextInteractor {
init {
- foldProvider.start()
+ applicationScope.launch {
+ foldProvider.start()
+ }
}
override val displayState =
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/CredentialPasswordView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/CredentialPasswordView.kt
index a3f34ce..eca0ada 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/CredentialPasswordView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/CredentialPasswordView.kt
@@ -53,7 +53,6 @@
subtitleView = requireViewById(R.id.subtitle)
descriptionView = requireViewById(R.id.description)
iconView = requireViewById(R.id.icon)
- subtitleView = requireViewById(R.id.subtitle)
passwordField = requireViewById(R.id.lockPassword)
credentialHeader = requireViewById(R.id.auth_credential_header)
credentialInput = requireViewById(R.id.auth_credential_input)
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
index b68b921..7b78761 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
@@ -93,9 +93,11 @@
val subtitleView = view.findViewById<TextView>(R.id.subtitle)
val descriptionView = view.findViewById<TextView>(R.id.description)
- // set selected for marquee
- titleView.isSelected = true
- subtitleView.isSelected = true
+ // set selected to enable marquee unless a screen reader is enabled
+ titleView.isSelected =
+ !accessibilityManager.isEnabled || !accessibilityManager.isTouchExplorationEnabled
+ subtitleView.isSelected =
+ !accessibilityManager.isEnabled || !accessibilityManager.isTouchExplorationEnabled
descriptionView.movementMethod = ScrollingMovementMethod()
val iconViewOverlay = view.findViewById<LottieAnimationView>(R.id.biometric_icon_overlay)
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactory.kt b/packages/SystemUI/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactory.kt
index 3206c00..1817ea9 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactory.kt
@@ -32,6 +32,7 @@
import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_PREPARE_FOR_UPDATE
import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_PRIMARY_AUTH_LOCKED_OUT
import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_RESTART
+import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_RESTART_FOR_MAINLINE_UPDATE
import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TIMEOUT
import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TRUSTAGENT_EXPIRED
import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_USER_REQUEST
@@ -53,6 +54,9 @@
import com.android.systemui.R.string.kg_primary_auth_locked_out_pattern
import com.android.systemui.R.string.kg_primary_auth_locked_out_pin
import com.android.systemui.R.string.kg_prompt_after_dpm_lock
+import com.android.systemui.R.string.kg_prompt_after_update_password
+import com.android.systemui.R.string.kg_prompt_after_update_pattern
+import com.android.systemui.R.string.kg_prompt_after_update_pin
import com.android.systemui.R.string.kg_prompt_after_user_lockdown_password
import com.android.systemui.R.string.kg_prompt_after_user_lockdown_pattern
import com.android.systemui.R.string.kg_prompt_after_user_lockdown_pin
@@ -89,69 +93,76 @@
fun createFromPromptReason(
@BouncerPromptReason reason: Int,
userId: Int,
+ secondaryMsgOverride: String? = null
): BouncerMessageModel? {
val pair =
getBouncerMessage(
reason,
securityModel.getSecurityMode(userId),
- updateMonitor.isFingerprintAllowedInBouncer
+ updateMonitor.isUnlockingWithFingerprintAllowed
)
return pair?.let {
BouncerMessageModel(
- message = Message(messageResId = pair.first),
- secondaryMessage = Message(messageResId = pair.second)
+ message = Message(messageResId = pair.first, animate = false),
+ secondaryMessage =
+ secondaryMsgOverride?.let {
+ Message(message = secondaryMsgOverride, animate = false)
+ }
+ ?: Message(messageResId = pair.second, animate = false)
)
}
}
- fun createFromString(
- primaryMsg: String? = null,
- secondaryMsg: String? = null
- ): BouncerMessageModel =
- BouncerMessageModel(
- message = primaryMsg?.let { Message(message = it) },
- secondaryMessage = secondaryMsg?.let { Message(message = it) },
- )
-
/**
* Helper method that provides the relevant bouncer message that should be shown for different
- * scenarios indicated by [reason]. [securityMode] & [fpAllowedInBouncer] parameters are used to
+ * scenarios indicated by [reason]. [securityMode] & [fpAuthIsAllowed] parameters are used to
* provide a more specific message.
*/
private fun getBouncerMessage(
@BouncerPromptReason reason: Int,
securityMode: SecurityMode,
- fpAllowedInBouncer: Boolean = false
+ fpAuthIsAllowed: Boolean = false
): Pair<Int, Int>? {
return when (reason) {
+ // Primary auth locked out
+ PROMPT_REASON_PRIMARY_AUTH_LOCKED_OUT -> primaryAuthLockedOut(securityMode)
+ // Primary auth required reasons
PROMPT_REASON_RESTART -> authRequiredAfterReboot(securityMode)
PROMPT_REASON_TIMEOUT -> authRequiredAfterPrimaryAuthTimeout(securityMode)
PROMPT_REASON_DEVICE_ADMIN -> authRequiredAfterAdminLockdown(securityMode)
PROMPT_REASON_USER_REQUEST -> authRequiredAfterUserLockdown(securityMode)
- PROMPT_REASON_AFTER_LOCKOUT -> biometricLockout(securityMode)
PROMPT_REASON_PREPARE_FOR_UPDATE -> authRequiredForUnattendedUpdate(securityMode)
+ PROMPT_REASON_RESTART_FOR_MAINLINE_UPDATE -> authRequiredForMainlineUpdate(securityMode)
PROMPT_REASON_FINGERPRINT_LOCKED_OUT -> fingerprintUnlockUnavailable(securityMode)
- PROMPT_REASON_FACE_LOCKED_OUT -> faceUnlockUnavailable(securityMode)
- PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT ->
- if (fpAllowedInBouncer) incorrectSecurityInputWithFingerprint(securityMode)
- else incorrectSecurityInput(securityMode)
+ PROMPT_REASON_AFTER_LOCKOUT -> biometricLockout(securityMode)
+ // Non strong auth not available reasons
+ PROMPT_REASON_FACE_LOCKED_OUT ->
+ if (fpAuthIsAllowed) faceLockedOutButFingerprintAvailable(securityMode)
+ else faceLockedOut(securityMode)
PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT ->
- if (fpAllowedInBouncer) nonStrongAuthTimeoutWithFingerprintAllowed(securityMode)
+ if (fpAuthIsAllowed) nonStrongAuthTimeoutWithFingerprintAllowed(securityMode)
else nonStrongAuthTimeout(securityMode)
PROMPT_REASON_TRUSTAGENT_EXPIRED ->
- if (fpAllowedInBouncer) trustAgentDisabledWithFingerprintAllowed(securityMode)
+ if (fpAuthIsAllowed) trustAgentDisabledWithFingerprintAllowed(securityMode)
else trustAgentDisabled(securityMode)
+ // Auth incorrect input reasons.
+ PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT ->
+ if (fpAuthIsAllowed) incorrectSecurityInputWithFingerprint(securityMode)
+ else incorrectSecurityInput(securityMode)
PROMPT_REASON_INCORRECT_FACE_INPUT ->
- if (fpAllowedInBouncer) incorrectFaceInputWithFingerprintAllowed(securityMode)
+ if (fpAuthIsAllowed) incorrectFaceInputWithFingerprintAllowed(securityMode)
else incorrectFaceInput(securityMode)
PROMPT_REASON_INCORRECT_FINGERPRINT_INPUT -> incorrectFingerprintInput(securityMode)
+ // Default message
PROMPT_REASON_DEFAULT ->
- if (fpAllowedInBouncer) defaultMessageWithFingerprint(securityMode)
+ if (fpAuthIsAllowed) defaultMessageWithFingerprint(securityMode)
else defaultMessage(securityMode)
- PROMPT_REASON_PRIMARY_AUTH_LOCKED_OUT -> primaryAuthLockedOut(securityMode)
else -> null
}
}
+
+ fun emptyMessage(): BouncerMessageModel =
+ BouncerMessageModel(Message(message = ""), Message(message = ""))
}
@Retention(AnnotationRetention.SOURCE)
@@ -172,6 +183,7 @@
PROMPT_REASON_NONE,
PROMPT_REASON_RESTART,
PROMPT_REASON_PRIMARY_AUTH_LOCKED_OUT,
+ PROMPT_REASON_RESTART_FOR_MAINLINE_UPDATE,
)
annotation class BouncerPromptReason
@@ -284,6 +296,15 @@
}
}
+private fun authRequiredForMainlineUpdate(securityMode: SecurityMode): Pair<Int, Int> {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_after_update_pattern)
+ SecurityMode.Password -> Pair(keyguard_enter_password, kg_prompt_after_update_password)
+ SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_prompt_after_update_pin)
+ else -> Pair(0, 0)
+ }
+}
+
private fun authRequiredAfterPrimaryAuthTimeout(securityMode: SecurityMode): Pair<Int, Int> {
return when (securityMode) {
SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_pattern_auth_timeout)
@@ -311,7 +332,7 @@
}
}
-private fun faceUnlockUnavailable(securityMode: SecurityMode): Pair<Int, Int> {
+private fun faceLockedOut(securityMode: SecurityMode): Pair<Int, Int> {
return when (securityMode) {
SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_face_locked_out)
SecurityMode.Password -> Pair(keyguard_enter_password, kg_face_locked_out)
@@ -320,6 +341,15 @@
}
}
+private fun faceLockedOutButFingerprintAvailable(securityMode: SecurityMode): Pair<Int, Int> {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(kg_unlock_with_pattern_or_fp, kg_face_locked_out)
+ SecurityMode.Password -> Pair(kg_unlock_with_password_or_fp, kg_face_locked_out)
+ SecurityMode.PIN -> Pair(kg_unlock_with_pin_or_fp, kg_face_locked_out)
+ else -> Pair(0, 0)
+ }
+}
+
private fun fingerprintUnlockUnavailable(securityMode: SecurityMode): Pair<Int, Int> {
return when (securityMode) {
SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_fp_locked_out)
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/BouncerMessageRepository.kt b/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/BouncerMessageRepository.kt
index 7e420cf..6fb0d4c 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/BouncerMessageRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/BouncerMessageRepository.kt
@@ -28,6 +28,7 @@
import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT
import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_PREPARE_FOR_UPDATE
import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_RESTART
+import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_RESTART_FOR_MAINLINE_UPDATE
import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TIMEOUT
import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TRUSTAGENT_EXPIRED
import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_USER_REQUEST
@@ -38,6 +39,7 @@
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.flags.SystemPropertiesHelper
import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository
import com.android.systemui.keyguard.data.repository.TrustRepository
@@ -105,6 +107,9 @@
fun clearMessage()
}
+private const val SYS_BOOT_REASON_PROP = "sys.boot.reason.last"
+private const val REBOOT_MAINLINE_UPDATE = "reboot,mainline_update"
+
@SysUISingleton
class BouncerMessageRepositoryImpl
@Inject
@@ -114,6 +119,7 @@
updateMonitor: KeyguardUpdateMonitor,
private val bouncerMessageFactory: BouncerMessageFactory,
private val userRepository: UserRepository,
+ private val systemPropertiesHelper: SystemPropertiesHelper,
fingerprintAuthRepository: DeviceEntryFingerprintAuthRepository,
) : BouncerMessageRepository {
@@ -132,6 +138,9 @@
private val isAnyBiometricsEnabledAndEnrolled =
or(isFaceEnrolledAndEnabled, isFingerprintEnrolledAndEnabled)
+ private val wasRebootedForMainlineUpdate
+ get() = systemPropertiesHelper.get(SYS_BOOT_REASON_PROP) == REBOOT_MAINLINE_UPDATE
+
private val authFlagsBasedPromptReason: Flow<Int> =
combine(
biometricSettingsRepository.authenticationFlags,
@@ -144,7 +153,8 @@
return@map if (
trustOrBiometricsAvailable && flags.isPrimaryAuthRequiredAfterReboot
) {
- PROMPT_REASON_RESTART
+ if (wasRebootedForMainlineUpdate) PROMPT_REASON_RESTART_FOR_MAINLINE_UPDATE
+ else PROMPT_REASON_RESTART
} else if (trustOrBiometricsAvailable && flags.isPrimaryAuthRequiredAfterTimeout) {
PROMPT_REASON_TIMEOUT
} else if (flags.isPrimaryAuthRequiredAfterDpmLockdown) {
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 d8cf398..8ed964d 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
@@ -127,10 +127,12 @@
repository.setMessage(message ?: promptMessage(getAuthenticationMethod()))
sceneInteractor.setCurrentScene(
scene = SceneModel(SceneKey.Bouncer),
+ loggingReason = "request to unlock device while authentication required",
)
} else {
sceneInteractor.setCurrentScene(
scene = SceneModel(SceneKey.Gone),
+ loggingReason = "request to unlock device while authentication isn't required",
)
}
}
@@ -176,6 +178,7 @@
if (isAuthenticated) {
sceneInteractor.setCurrentScene(
scene = SceneModel(SceneKey.Gone),
+ loggingReason = "successful authentication",
)
} else {
repository.setMessage(errorMessage(getAuthenticationMethod()))
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractor.kt
index d06dd8e..fe01d08 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractor.kt
@@ -86,7 +86,11 @@
repository.setFingerprintAcquisitionMessage(
if (value != null) {
- factory.createFromString(secondaryMsg = value)
+ factory.createFromPromptReason(
+ PROMPT_REASON_DEFAULT,
+ userRepository.getSelectedUserInfo().id,
+ secondaryMsgOverride = value
+ )
} else {
null
}
@@ -98,7 +102,11 @@
repository.setFaceAcquisitionMessage(
if (value != null) {
- factory.createFromString(secondaryMsg = value)
+ factory.createFromPromptReason(
+ PROMPT_REASON_DEFAULT,
+ userRepository.getSelectedUserInfo().id,
+ secondaryMsgOverride = value
+ )
} else {
null
}
@@ -110,7 +118,11 @@
repository.setCustomMessage(
if (value != null) {
- factory.createFromString(secondaryMsg = value)
+ factory.createFromPromptReason(
+ PROMPT_REASON_DEFAULT,
+ userRepository.getSelectedUserInfo().id,
+ secondaryMsgOverride = value
+ )
} else {
null
}
@@ -140,8 +152,7 @@
// always maps to an empty string.
private fun nullOrEmptyMessage() =
flowOf(
- if (featureFlags.isEnabled(REVAMPED_BOUNCER_MESSAGES)) null
- else factory.createFromString("", "")
+ if (featureFlags.isEnabled(REVAMPED_BOUNCER_MESSAGES)) null else factory.emptyMessage()
)
val bouncerMessage =
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/BouncerMessageView.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/BouncerMessageView.kt
index 47fac2b..6486802 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/BouncerMessageView.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/BouncerMessageView.kt
@@ -41,8 +41,6 @@
super.onFinishInflate()
primaryMessageView = findViewById(R.id.bouncer_primary_message_area)
secondaryMessageView = findViewById(R.id.bouncer_secondary_message_area)
- primaryMessageView?.disable()
- secondaryMessageView?.disable()
}
fun init(factory: KeyguardMessageAreaController.Factory) {
diff --git a/packages/SystemUI/src/com/android/systemui/complication/DreamClockTimeComplication.java b/packages/SystemUI/src/com/android/systemui/complication/DreamClockTimeComplication.java
index 9c3448b..dc32a59 100644
--- a/packages/SystemUI/src/com/android/systemui/complication/DreamClockTimeComplication.java
+++ b/packages/SystemUI/src/com/android/systemui/complication/DreamClockTimeComplication.java
@@ -16,34 +16,36 @@
package com.android.systemui.complication;
-import static com.android.systemui.complication.dagger.DreamClockTimeComplicationModule.DREAM_CLOCK_TIME_COMPLICATION_VIEW;
+import static com.android.systemui.complication.dagger.DreamClockTimeComplicationComponent.DreamClockTimeComplicationModule.DREAM_CLOCK_TIME_COMPLICATION_VIEW;
import static com.android.systemui.complication.dagger.RegisteredComplicationsModule.DREAM_CLOCK_TIME_COMPLICATION_LAYOUT_PARAMS;
import android.view.View;
+import com.android.internal.logging.UiEventLogger;
import com.android.systemui.CoreStartable;
+import com.android.systemui.complication.dagger.DreamClockTimeComplicationComponent;
import com.android.systemui.dagger.qualifiers.SystemUser;
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.shared.condition.Monitor;
+import com.android.systemui.util.ViewController;
import com.android.systemui.util.condition.ConditionalCoreStartable;
import javax.inject.Inject;
import javax.inject.Named;
-import javax.inject.Provider;
/**
* Clock Time Complication that produce Clock Time view holder.
*/
public class DreamClockTimeComplication implements Complication {
- private final Provider<DreamClockTimeViewHolder> mDreamClockTimeViewHolderProvider;
+ private final DreamClockTimeComplicationComponent.Factory mComponentFactory;
/**
* Default constructor for {@link DreamClockTimeComplication}.
*/
@Inject
public DreamClockTimeComplication(
- Provider<DreamClockTimeViewHolder> dreamClockTimeViewHolderProvider) {
- mDreamClockTimeViewHolderProvider = dreamClockTimeViewHolderProvider;
+ DreamClockTimeComplicationComponent.Factory componentFactory) {
+ mComponentFactory = componentFactory;
}
@Override
@@ -56,7 +58,7 @@
*/
@Override
public ViewHolder createView(ComplicationViewModel model) {
- return mDreamClockTimeViewHolderProvider.get();
+ return mComponentFactory.create().getViewHolder();
}
/**
@@ -94,11 +96,14 @@
private final ComplicationLayoutParams mLayoutParams;
@Inject
- DreamClockTimeViewHolder(@Named(DREAM_CLOCK_TIME_COMPLICATION_VIEW) View view,
+ DreamClockTimeViewHolder(
+ @Named(DREAM_CLOCK_TIME_COMPLICATION_VIEW) View view,
@Named(DREAM_CLOCK_TIME_COMPLICATION_LAYOUT_PARAMS)
- ComplicationLayoutParams layoutParams) {
+ ComplicationLayoutParams layoutParams,
+ DreamClockTimeViewController viewController) {
mView = view;
mLayoutParams = layoutParams;
+ viewController.init();
}
@Override
@@ -111,4 +116,29 @@
return mLayoutParams;
}
}
+
+ static class DreamClockTimeViewController extends ViewController<View> {
+ private final UiEventLogger mUiEventLogger;
+
+ @Inject
+ DreamClockTimeViewController(
+ @Named(DREAM_CLOCK_TIME_COMPLICATION_VIEW) View view,
+ UiEventLogger uiEventLogger) {
+ super(view);
+
+ mUiEventLogger = uiEventLogger;
+ }
+
+ @Override
+ protected void onViewAttached() {
+ mView.setOnClickListener(this::onClick);
+ }
+
+ @Override
+ protected void onViewDetached() {}
+
+ private void onClick(View v) {
+ mUiEventLogger.log(DreamOverlayUiEvent.DREAM_CLOCK_TAPPED);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/complication/DreamHomeControlsComplication.java b/packages/SystemUI/src/com/android/systemui/complication/DreamHomeControlsComplication.java
index 4d99282..7ac1cc7 100644
--- a/packages/SystemUI/src/com/android/systemui/complication/DreamHomeControlsComplication.java
+++ b/packages/SystemUI/src/com/android/systemui/complication/DreamHomeControlsComplication.java
@@ -29,8 +29,6 @@
import android.view.View;
import android.widget.ImageView;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.CoreStartable;
import com.android.systemui.animation.ActivityLaunchAnimator;
@@ -201,23 +199,6 @@
private final UiEventLogger mUiEventLogger;
- @VisibleForTesting
- public enum DreamOverlayEvent implements UiEventLogger.UiEventEnum {
- @UiEvent(doc = "The home controls on the screensaver has been tapped.")
- DREAM_HOME_CONTROLS_TAPPED(1212);
-
- private final int mId;
-
- DreamOverlayEvent(int id) {
- mId = id;
- }
-
- @Override
- public int getId() {
- return mId;
- }
- }
-
@Inject
DreamHomeControlsChipViewController(
@Named(DREAM_HOME_CONTROLS_CHIP_VIEW) ImageView view,
@@ -246,7 +227,7 @@
private void onClickHomeControls(View v) {
if (DEBUG) Log.d(TAG, "home controls complication tapped");
- mUiEventLogger.log(DreamOverlayEvent.DREAM_HOME_CONTROLS_TAPPED);
+ mUiEventLogger.log(DreamOverlayUiEvent.DREAM_HOME_CONTROLS_TAPPED);
final Intent intent = new Intent(mContext, ControlsActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK)
diff --git a/packages/SystemUI/src/com/android/systemui/complication/DreamOverlayUiEvent.kt b/packages/SystemUI/src/com/android/systemui/complication/DreamOverlayUiEvent.kt
new file mode 100644
index 0000000..17cc829
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/complication/DreamOverlayUiEvent.kt
@@ -0,0 +1,32 @@
+/*
+ * 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.complication
+
+import com.android.internal.logging.UiEvent
+import com.android.internal.logging.UiEventLogger.UiEventEnum
+
+/** UI log events for the dream overlay. */
+enum class DreamOverlayUiEvent(private val mId: Int) : UiEventEnum {
+ @UiEvent(doc = "The home controls on the screensaver has been tapped.")
+ DREAM_HOME_CONTROLS_TAPPED(1212),
+ @UiEvent(doc = "The clock on the screensaver has been tapped") DREAM_CLOCK_TAPPED(1440),
+ @UiEvent(doc = "The weather on the screensaver has been tapped") DREAM_WEATHER_TAPPED(1441);
+
+ override fun getId(): Int {
+ return mId
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/complication/dagger/DreamClockTimeComplicationComponent.kt b/packages/SystemUI/src/com/android/systemui/complication/dagger/DreamClockTimeComplicationComponent.kt
new file mode 100644
index 0000000..87c3b2f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/complication/dagger/DreamClockTimeComplicationComponent.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.complication.dagger
+
+import android.view.LayoutInflater
+import android.view.View
+import android.widget.TextClock
+import com.android.internal.util.Preconditions
+import com.android.systemui.R
+import com.android.systemui.complication.DreamClockTimeComplication
+import com.android.systemui.complication.DreamClockTimeComplication.DreamClockTimeViewHolder
+import dagger.Module
+import dagger.Provides
+import dagger.Subcomponent
+import javax.inject.Named
+import javax.inject.Scope
+
+/** Responsible for generating dependencies for the [DreamClockTimeComplication]. */
+@Subcomponent(
+ modules = [DreamClockTimeComplicationComponent.DreamClockTimeComplicationModule::class]
+)
+@DreamClockTimeComplicationComponent.DreamClockTimeComplicationScope
+interface DreamClockTimeComplicationComponent {
+ /** Scope of the clock complication. */
+ @MustBeDocumented
+ @Retention(AnnotationRetention.RUNTIME)
+ @Scope
+ annotation class DreamClockTimeComplicationScope
+
+ /** Factory that generates a component for the clock complication. */
+ @Subcomponent.Factory
+ interface Factory {
+ fun create(): DreamClockTimeComplicationComponent
+ }
+
+ /** Creates a view holder for the clock complication. */
+ fun getViewHolder(): DreamClockTimeViewHolder
+
+ /** Module for providing injected values within the clock complication scope. */
+ @Module
+ interface DreamClockTimeComplicationModule {
+ companion object {
+ const val DREAM_CLOCK_TIME_COMPLICATION_VIEW = "clock_time_complication_view"
+ private const val TAG_WEIGHT = "'wght' "
+ private const val WEIGHT = 400
+
+ /** Provides the complication view. */
+ @Provides
+ @DreamClockTimeComplicationScope
+ @Named(DREAM_CLOCK_TIME_COMPLICATION_VIEW)
+ fun provideComplicationView(layoutInflater: LayoutInflater): View {
+ val view =
+ Preconditions.checkNotNull(
+ layoutInflater.inflate(
+ R.layout.dream_overlay_complication_clock_time,
+ /* root = */ null,
+ /* attachToRoot = */ false,
+ ) as TextClock,
+ "R.layout.dream_overlay_complication_clock_time did not properly inflate"
+ )
+ view.setFontVariationSettings(TAG_WEIGHT + WEIGHT)
+ return view
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/complication/dagger/DreamClockTimeComplicationModule.java b/packages/SystemUI/src/com/android/systemui/complication/dagger/DreamClockTimeComplicationModule.java
deleted file mode 100644
index fd711ee..0000000
--- a/packages/SystemUI/src/com/android/systemui/complication/dagger/DreamClockTimeComplicationModule.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.complication.dagger;
-
-
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.TextClock;
-
-import com.android.internal.util.Preconditions;
-import com.android.systemui.R;
-import com.android.systemui.complication.DreamClockTimeComplication;
-
-import dagger.Module;
-import dagger.Provides;
-
-import javax.inject.Named;
-
-/**
- * Module for providing {@link DreamClockTimeComplication}.
- */
-@Module
-public interface DreamClockTimeComplicationModule {
- String DREAM_CLOCK_TIME_COMPLICATION_VIEW = "clock_time_complication_view";
- String TAG_WEIGHT = "'wght' ";
- int WEIGHT = 400;
-
- /**
- * Provides the complication view.
- */
- @Provides
- @Named(DREAM_CLOCK_TIME_COMPLICATION_VIEW)
- static View provideComplicationView(LayoutInflater layoutInflater) {
- final View view = Preconditions.checkNotNull(
- layoutInflater.inflate(R.layout.dream_overlay_complication_clock_time,
- null, false),
- "R.layout.dream_overlay_complication_clock_time did not properly inflated");
- ((TextClock) view.findViewById(R.id.time_view)).setFontVariationSettings(
- TAG_WEIGHT + WEIGHT);
- return view;
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/complication/dagger/RegisteredComplicationsModule.java b/packages/SystemUI/src/com/android/systemui/complication/dagger/RegisteredComplicationsModule.java
index 98975fbd..776c972 100644
--- a/packages/SystemUI/src/com/android/systemui/complication/dagger/RegisteredComplicationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/complication/dagger/RegisteredComplicationsModule.java
@@ -35,10 +35,9 @@
* Module for all components with corresponding dream layer complications registered in
* {@link SystemUIBinder}.
*/
-@Module(includes = {
- DreamClockTimeComplicationModule.class,
- },
+@Module(
subcomponents = {
+ DreamClockTimeComplicationComponent.class,
DreamHomeControlsComplicationComponent.class,
DreamMediaEntryComplicationComponent.class
})
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 6518c8c..e471836 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -195,10 +195,10 @@
@JvmField val FALSING_OFF_FOR_UNFOLDED = releasedFlag(225, "falsing_off_for_unfolded")
/** Enables code to show contextual loyalty cards in wallet entrypoints */
- // TODO(b/247587924): Tracking Bug
+ // TODO(b/294110497): Tracking Bug
@JvmField
val ENABLE_WALLET_CONTEXTUAL_LOYALTY_CARDS =
- unreleasedFlag(226, "enable_wallet_contextual_loyalty_cards", teamfood = false)
+ unreleasedFlag(226, "enable_wallet_contextual_loyalty_cards", teamfood = true)
// TODO(b/242908637): Tracking Bug
@JvmField val WALLPAPER_FULLSCREEN_PREVIEW = releasedFlag(227, "wallpaper_fullscreen_preview")
@@ -266,7 +266,7 @@
@JvmField val KEYGUARD_TALKBACK_FIX = releasedFlag(238, "keyguard_talkback_fix")
// TODO(b/287268101): Tracking bug.
- @JvmField val TRANSIT_CLOCK = unreleasedFlag(239, "lockscreen_custom_transit_clock")
+ @JvmField val TRANSIT_CLOCK = unreleasedFlag(239, "lockscreen_custom_transit_clock", teamfood = true)
/** Migrate the lock icon view to the new keyguard root view. */
// TODO(b/286552209): Tracking bug.
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
index 44e1fd1..cca96b7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
@@ -66,6 +66,23 @@
},
)
+ /** Lockscreen alpha */
+ val lockscreenAlpha: Flow<Float> =
+ transitionAnimation.createFlow(
+ duration = 50.milliseconds,
+ onStart = {
+ leaveShadeOpen = statusBarStateController.leaveOpenOnKeyguardHide()
+ willRunDismissFromKeyguard = primaryBouncerInteractor.willRunDismissFromKeyguard()
+ },
+ onStep = {
+ if (willRunDismissFromKeyguard || leaveShadeOpen) {
+ 1f
+ } else {
+ 0f
+ }
+ },
+ )
+
/** Scrim alpha values */
val scrimAlpha: Flow<ScrimAlpha> =
transitionAnimation
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 b5759e3..cc1504a 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -496,4 +496,12 @@
public static LogBuffer provideDisplayMetricsRepoLogBuffer(LogBufferFactory factory) {
return factory.create("DisplayMetricsRepo", 50);
}
+
+ /** Provides a {@link LogBuffer} for the scene framework. */
+ @Provides
+ @SysUISingleton
+ @SceneFrameworkLog
+ public static LogBuffer provideSceneFrameworkLogBuffer(LogBufferFactory factory) {
+ return factory.create("SceneFramework", 50);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/SceneFrameworkLog.kt b/packages/SystemUI/src/com/android/systemui/log/dagger/SceneFrameworkLog.kt
new file mode 100644
index 0000000..ef5f4e3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/SceneFrameworkLog.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 the Scene Framework. */
+@Qualifier
+@MustBeDocumented
+@Retention(AnnotationRetention.RUNTIME)
+annotation class SceneFrameworkLog
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java
index b4578e9..11a16a4 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java
@@ -261,7 +261,10 @@
mMediaOutputController.registerLeBroadcastAssistantServiceCallback(mExecutor,
mBroadcastAssistantCallback);
}
- connectBroadcastWithActiveDevice();
+ /* Add local source broadcast to connected capable devices that may be possible receivers
+ * of stream.
+ */
+ startBroadcastWithConnectedDevices();
}
@Override
@@ -394,30 +397,26 @@
}
}
- void connectBroadcastWithActiveDevice() {
+ void startBroadcastWithConnectedDevices() {
//get the Metadata, and convert to BT QR code format.
BluetoothLeBroadcastMetadata broadcastMetadata = getBroadcastMetadata();
if (broadcastMetadata == null) {
Log.e(TAG, "Error: There is no broadcastMetadata.");
return;
}
- MediaDevice mediaDevice = mMediaOutputController.getCurrentConnectedMediaDevice();
- if (mediaDevice == null || !(mediaDevice instanceof BluetoothMediaDevice)
- || !mediaDevice.isBLEDevice()) {
- Log.e(TAG, "Error: There is no active BT LE device.");
- return;
- }
- BluetoothDevice sink = ((BluetoothMediaDevice) mediaDevice).getCachedDevice().getDevice();
- Log.d(TAG, "The broadcastMetadata broadcastId: " + broadcastMetadata.getBroadcastId()
- + ", the device: " + sink.getAnonymizedAddress());
- if (mMediaOutputController.isThereAnyBroadcastSourceIntoSinkDevice(sink)) {
- Log.d(TAG, "The sink device has the broadcast source now.");
- return;
- }
- if (!mMediaOutputController.addSourceIntoSinkDeviceWithBluetoothLeAssistant(sink,
- broadcastMetadata, /*isGroupOp=*/ true)) {
- Log.e(TAG, "Error: Source add failed");
+ for (BluetoothDevice sink : mMediaOutputController.getConnectedBroadcastSinkDevices()) {
+ Log.d(TAG, "The broadcastMetadata broadcastId: " + broadcastMetadata.getBroadcastId()
+ + ", the device: " + sink.getAnonymizedAddress());
+
+ if (mMediaOutputController.isThereAnyBroadcastSourceIntoSinkDevice(sink)) {
+ Log.d(TAG, "The sink device has the broadcast source now.");
+ return;
+ }
+ if (!mMediaOutputController.addSourceIntoSinkDeviceWithBluetoothLeAssistant(sink,
+ broadcastMetadata, /*isGroupOp=*/ false)) {
+ Log.e(TAG, "Error: Source add failed");
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index be42569..d281f50 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -983,7 +983,7 @@
LocalBluetoothLeBroadcast broadcast =
mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile();
if (broadcast == null) {
- Log.d(TAG, "getBroadcastMetadata: LE Audio Broadcast is null");
+ Log.d(TAG, "getLocalBroadcastMetadataQrCodeString: LE Audio Broadcast is null");
return "";
}
final LocalBluetoothLeBroadcastMetadata metadata =
@@ -1087,11 +1087,23 @@
broadcast.unregisterServiceCallBack(callback);
}
+ List<BluetoothDevice> getConnectedBroadcastSinkDevices() {
+ LocalBluetoothLeBroadcastAssistant assistant =
+ mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastAssistantProfile();
+ if (assistant == null) {
+ Log.d(TAG, "getConnectedBroadcastSinkDevices: The broadcast assistant profile is null");
+ return null;
+ }
+
+ return assistant.getConnectedDevices();
+ }
+
boolean isThereAnyBroadcastSourceIntoSinkDevice(BluetoothDevice sink) {
LocalBluetoothLeBroadcastAssistant assistant =
mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastAssistantProfile();
if (assistant == null) {
- Log.d(TAG, "The broadcast assistant profile is null");
+ Log.d(TAG, "isThereAnyBroadcastSourceIntoSinkDevice: The broadcast assistant profile "
+ + "is null");
return false;
}
List<BluetoothLeBroadcastReceiveState> sourceList = assistant.getAllSources(sink);
@@ -1104,7 +1116,8 @@
LocalBluetoothLeBroadcastAssistant assistant =
mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastAssistantProfile();
if (assistant == null) {
- Log.d(TAG, "The broadcast assistant profile is null");
+ Log.d(TAG, "addSourceIntoSinkDeviceWithBluetoothLeAssistant: The broadcast assistant "
+ + "profile is null");
return false;
}
assistant.addSource(sink, metadata, isGroupOp);
@@ -1117,7 +1130,8 @@
LocalBluetoothLeBroadcastAssistant assistant =
mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastAssistantProfile();
if (assistant == null) {
- Log.d(TAG, "The broadcast assistant profile is null");
+ Log.d(TAG, "registerLeBroadcastAssistantServiceCallback: The broadcast assistant "
+ + "profile is null");
return;
}
Log.d(TAG, "Register LE broadcast assistant callback");
@@ -1129,7 +1143,8 @@
LocalBluetoothLeBroadcastAssistant assistant =
mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastAssistantProfile();
if (assistant == null) {
- Log.d(TAG, "The broadcast assistant profile is null");
+ Log.d(TAG, "unregisterLeBroadcastAssistantServiceCallback: The broadcast assistant "
+ + "profile is null");
return;
}
Log.d(TAG, "Unregister LE broadcast assistant callback");
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 03bd11b..9f45f66 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -220,7 +220,7 @@
// If scene framework is enabled, set the scene container window to
// visible and let the touch "slip" into that window.
if (mFeatureFlags.isEnabled(Flags.SCENE_CONTAINER)) {
- mSceneInteractor.get().setVisible(true);
+ mSceneInteractor.get().setVisible(true, "swipe down on launcher");
} else {
centralSurfaces.onInputFocusTransfer(
mInputFocusTransferStarted, false /* cancel */,
diff --git a/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt b/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt
index 1fca488..fee3960 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt
@@ -14,16 +14,23 @@
* limitations under the License.
*/
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
package com.android.systemui.scene.data.repository
+import com.android.systemui.scene.shared.model.ObservableTransitionState
import com.android.systemui.scene.shared.model.SceneContainerConfig
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import com.android.systemui.scene.shared.model.SceneTransitionModel
import javax.inject.Inject
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
/** Source of truth for scene framework application state. */
class SceneContainerRepository
@@ -38,8 +45,17 @@
private val _currentScene = MutableStateFlow(SceneModel(config.initialSceneKey))
val currentScene: StateFlow<SceneModel> = _currentScene.asStateFlow()
- private val _transitionProgress = MutableStateFlow(1f)
- val transitionProgress: StateFlow<Float> = _transitionProgress.asStateFlow()
+ private val transitionState = MutableStateFlow<Flow<ObservableTransitionState>?>(null)
+ val transitionProgress: Flow<Float> =
+ transitionState.flatMapLatest { observableTransitionStateFlow ->
+ observableTransitionStateFlow?.flatMapLatest { observableTransitionState ->
+ when (observableTransitionState) {
+ is ObservableTransitionState.Idle -> flowOf(1f)
+ is ObservableTransitionState.Transition -> observableTransitionState.progress
+ }
+ }
+ ?: flowOf(1f)
+ }
private val _transitions = MutableStateFlow<SceneTransitionModel?>(null)
val transitions: StateFlow<SceneTransitionModel?> = _transitions.asStateFlow()
@@ -92,8 +108,12 @@
_isVisible.value = isVisible
}
- /** Sets scene transition progress to the current scene in the container with the given name. */
- fun setSceneTransitionProgress(progress: Float) {
- _transitionProgress.value = progress
+ /**
+ * Binds the given flow so the system remembers it.
+ *
+ * Note that you must call is with `null` when the UI is done or risk a memory leak.
+ */
+ fun setTransitionState(transitionState: Flow<ObservableTransitionState>?) {
+ this.transitionState.value = transitionState
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
index 39daad3..64715bc 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
@@ -18,11 +18,14 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.scene.data.repository.SceneContainerRepository
+import com.android.systemui.scene.shared.logger.SceneLogger
+import com.android.systemui.scene.shared.model.ObservableTransitionState
import com.android.systemui.scene.shared.model.RemoteUserInput
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import com.android.systemui.scene.shared.model.SceneTransitionModel
import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
@@ -39,6 +42,7 @@
@Inject
constructor(
private val repository: SceneContainerRepository,
+ private val logger: SceneLogger,
) {
/**
@@ -52,8 +56,17 @@
}
/** Sets the scene in the container with the given name. */
- fun setCurrentScene(scene: SceneModel) {
+ fun setCurrentScene(scene: SceneModel, loggingReason: String) {
val currentSceneKey = repository.currentScene.value.key
+ if (currentSceneKey == scene.key) {
+ return
+ }
+
+ logger.logSceneChange(
+ from = currentSceneKey,
+ to = scene.key,
+ reason = loggingReason,
+ )
repository.setCurrentScene(scene)
repository.setSceneTransition(from = currentSceneKey, to = scene.key)
}
@@ -62,20 +75,34 @@
val currentScene: StateFlow<SceneModel> = repository.currentScene
/** Sets the visibility of the container with the given name. */
- fun setVisible(isVisible: Boolean) {
+ fun setVisible(isVisible: Boolean, loggingReason: String) {
+ val wasVisible = repository.isVisible.value
+ if (wasVisible == isVisible) {
+ return
+ }
+
+ logger.logVisibilityChange(
+ from = wasVisible,
+ to = isVisible,
+ reason = loggingReason,
+ )
return repository.setVisible(isVisible)
}
/** Whether the container with the given name is visible. */
val isVisible: StateFlow<Boolean> = repository.isVisible
- /** Sets scene transition progress to the current scene in the container with the given name. */
- fun setSceneTransitionProgress(progress: Float) {
- repository.setSceneTransitionProgress(progress)
+ /**
+ * Binds the given flow so the system remembers it.
+ *
+ * Note that you must call is with `null` when the UI is done or risk a memory leak.
+ */
+ fun setTransitionState(transitionState: Flow<ObservableTransitionState>?) {
+ repository.setTransitionState(transitionState)
}
/** Progress of the transition into the current scene in the container with the given name. */
- val transitionProgress: StateFlow<Float> = repository.transitionProgress
+ val transitionProgress: Flow<Float> = repository.transitionProgress
/**
* Scene transitions as pairs of keys. A new value is emitted exactly once, each time a scene
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
index 1c87eb2..20ee393 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
@@ -28,6 +28,7 @@
import com.android.systemui.model.SysUiState
import com.android.systemui.model.updateFlags
import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.shared.logger.SceneLogger
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING
@@ -57,13 +58,17 @@
private val featureFlags: FeatureFlags,
private val sysUiState: SysUiState,
@DisplayId private val displayId: Int,
+ private val sceneLogger: SceneLogger,
) : CoreStartable {
override fun start() {
if (featureFlags.isEnabled(Flags.SCENE_CONTAINER)) {
+ sceneLogger.logFrameworkEnabled(isEnabled = true)
hydrateVisibility()
automaticallySwitchScenes()
hydrateSystemUiState()
+ } else {
+ sceneLogger.logFrameworkEnabled(isEnabled = false)
}
}
@@ -73,7 +78,9 @@
sceneInteractor.currentScene
.map { it.key }
.distinctUntilChanged()
- .collect { sceneKey -> sceneInteractor.setVisible(sceneKey != SceneKey.Gone) }
+ .collect { sceneKey ->
+ sceneInteractor.setVisible(sceneKey != SceneKey.Gone, "scene is $sceneKey")
+ }
}
}
@@ -88,10 +95,17 @@
isUnlocked ->
when (currentSceneKey) {
// When the device becomes unlocked in Bouncer, go to Gone.
- is SceneKey.Bouncer -> SceneKey.Gone
+ is SceneKey.Bouncer ->
+ SceneKey.Gone to "device unlocked in Bouncer scene"
// When the device becomes unlocked in Lockscreen, go to Gone if
// bypass is enabled.
- is SceneKey.Lockscreen -> SceneKey.Gone.takeIf { isBypassEnabled }
+ is SceneKey.Lockscreen ->
+ if (isBypassEnabled) {
+ SceneKey.Gone to
+ "device unlocked in Lockscreen scene with bypass"
+ } else {
+ null
+ }
// We got unlocked while on a scene that's not Lockscreen or
// Bouncer, no need to change scenes.
else -> null
@@ -104,13 +118,19 @@
is SceneKey.Bouncer -> null
// We got locked while on a scene that's not Lockscreen or Bouncer,
// go to Lockscreen.
- else -> SceneKey.Lockscreen
+ else ->
+ SceneKey.Lockscreen to "device locked in $currentSceneKey scene"
}
else -> null
}
}
.filterNotNull()
- .collect { targetSceneKey -> switchToScene(targetSceneKey) }
+ .collect { (targetSceneKey, loggingReason) ->
+ switchToScene(
+ targetSceneKey = targetSceneKey,
+ loggingReason = loggingReason,
+ )
+ }
}
applicationScope.launch {
@@ -121,7 +141,16 @@
if (isAsleep) {
// When the device goes to sleep, reset the current scene.
val isUnlocked = authenticationInteractor.isUnlocked.value
- switchToScene(if (isUnlocked) SceneKey.Gone else SceneKey.Lockscreen)
+ val (targetSceneKey, loggingReason) =
+ if (isUnlocked) {
+ SceneKey.Gone to "device is asleep while unlocked"
+ } else {
+ SceneKey.Lockscreen to "device is asleep while locked"
+ }
+ switchToScene(
+ targetSceneKey = targetSceneKey,
+ loggingReason = loggingReason,
+ )
}
}
}
@@ -147,9 +176,10 @@
}
}
- private fun switchToScene(targetSceneKey: SceneKey) {
+ private fun switchToScene(targetSceneKey: SceneKey, loggingReason: String) {
sceneInteractor.setCurrentScene(
scene = SceneModel(targetSceneKey),
+ loggingReason = loggingReason,
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/logger/SceneLogger.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/logger/SceneLogger.kt
new file mode 100644
index 0000000..0adbd5a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/logger/SceneLogger.kt
@@ -0,0 +1,81 @@
+/*
+ * 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.scene.shared.logger
+
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.core.LogLevel
+import com.android.systemui.log.dagger.SceneFrameworkLog
+import com.android.systemui.scene.shared.model.SceneKey
+import javax.inject.Inject
+
+class SceneLogger @Inject constructor(@SceneFrameworkLog private val logBuffer: LogBuffer) {
+
+ fun logFrameworkEnabled(isEnabled: Boolean) {
+ fun asWord(isEnabled: Boolean): String {
+ return if (isEnabled) "enabled" else "disabled"
+ }
+
+ logBuffer.log(
+ tag = TAG,
+ level = LogLevel.INFO,
+ messageInitializer = { bool1 = isEnabled },
+ messagePrinter = { "Scene framework is ${asWord(bool1)}" }
+ )
+ }
+
+ fun logSceneChange(
+ from: SceneKey,
+ to: SceneKey,
+ reason: String,
+ ) {
+ logBuffer.log(
+ tag = TAG,
+ level = LogLevel.INFO,
+ messageInitializer = {
+ str1 = from.toString()
+ str2 = to.toString()
+ str3 = reason
+ },
+ messagePrinter = { "$str1 → $str2, reason: $str3" },
+ )
+ }
+
+ fun logVisibilityChange(
+ from: Boolean,
+ to: Boolean,
+ reason: String,
+ ) {
+ fun asWord(isVisible: Boolean): String {
+ return if (isVisible) "visible" else "invisible"
+ }
+
+ logBuffer.log(
+ tag = TAG,
+ level = LogLevel.INFO,
+ messageInitializer = {
+ str1 = asWord(from)
+ str2 = asWord(to)
+ str3 = reason
+ },
+ messagePrinter = { "$str1 → $str2, reason: $str3" },
+ )
+ }
+
+ companion object {
+ private const val TAG = "SceneFramework"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/ObservableTransitionState.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/ObservableTransitionState.kt
new file mode 100644
index 0000000..9a30aa6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/ObservableTransitionState.kt
@@ -0,0 +1,36 @@
+/*
+ * 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.scene.shared.model
+
+import kotlinx.coroutines.flow.Flow
+
+/**
+ * This is a fork of a class by the same name in the `com.android.compose.animation.scene` package.
+ *
+ * TODO(b/293899074): remove this fork, once we can compile Compose into System UI.
+ */
+sealed class ObservableTransitionState {
+ /** No transition/animation is currently running. */
+ data class Idle(val scene: SceneKey) : ObservableTransitionState()
+
+ /** There is a transition animating between two scenes. */
+ data class Transition(
+ val fromScene: SceneKey,
+ val toScene: SceneKey,
+ val progress: Flow<Float>,
+ ) : ObservableTransitionState()
+}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
index f44748a..b4ebaec 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
@@ -19,10 +19,12 @@
import android.view.MotionEvent
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.shared.model.ObservableTransitionState
import com.android.systemui.scene.shared.model.RemoteUserInput
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
/** Models UI state for the scene container. */
@@ -51,16 +53,27 @@
/** Requests a transition to the scene with the given key. */
fun setCurrentScene(scene: SceneModel) {
- interactor.setCurrentScene(scene)
+ interactor.setCurrentScene(
+ scene = scene,
+ loggingReason = SCENE_TRANSITION_LOGGING_REASON,
+ )
}
- /** Notifies of the progress of a scene transition. */
- fun setSceneTransitionProgress(progress: Float) {
- interactor.setSceneTransitionProgress(progress)
+ /**
+ * Binds the given flow so the system remembers it.
+ *
+ * Note that you must call is with `null` when the UI is done or risk a memory leak.
+ */
+ fun setTransitionState(transitionState: Flow<ObservableTransitionState>?) {
+ interactor.setTransitionState(transitionState)
}
/** Handles a [MotionEvent] representing remote user input. */
fun onRemoteUserInput(event: MotionEvent) {
interactor.onRemoteUserInput(RemoteUserInput.translateMotionEvent(event))
}
+
+ companion object {
+ private const val SCENE_TRANSITION_LOGGING_REASON = "user input"
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 2ea63c2..416f147 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -147,6 +147,7 @@
import com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel;
import com.android.systemui.keyguard.ui.viewmodel.LockscreenToOccludedTransitionViewModel;
import com.android.systemui.keyguard.ui.viewmodel.OccludedToLockscreenTransitionViewModel;
+import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel;
import com.android.systemui.media.controls.pipeline.MediaDataManager;
import com.android.systemui.media.controls.ui.KeyguardMediaController;
import com.android.systemui.media.controls.ui.MediaHierarchyManager;
@@ -602,6 +603,7 @@
mGoneToDreamingLockscreenHostedTransitionViewModel;
private final LockscreenToOccludedTransitionViewModel mLockscreenToOccludedTransitionViewModel;
+ private final PrimaryBouncerToGoneTransitionViewModel mPrimaryBouncerToGoneTransitionViewModel;
private final KeyguardTransitionInteractor mKeyguardTransitionInteractor;
private final KeyguardInteractor mKeyguardInteractor;
@@ -761,6 +763,7 @@
GoneToDreamingLockscreenHostedTransitionViewModel
goneToDreamingLockscreenHostedTransitionViewModel,
LockscreenToOccludedTransitionViewModel lockscreenToOccludedTransitionViewModel,
+ PrimaryBouncerToGoneTransitionViewModel primaryBouncerToGoneTransitionViewModel,
@Main CoroutineDispatcher mainDispatcher,
KeyguardTransitionInteractor keyguardTransitionInteractor,
DumpManager dumpManager,
@@ -790,6 +793,7 @@
mGoneToDreamingLockscreenHostedTransitionViewModel =
goneToDreamingLockscreenHostedTransitionViewModel;
mLockscreenToOccludedTransitionViewModel = lockscreenToOccludedTransitionViewModel;
+ mPrimaryBouncerToGoneTransitionViewModel = primaryBouncerToGoneTransitionViewModel;
mKeyguardTransitionInteractor = keyguardTransitionInteractor;
mKeyguardInteractor = keyguardInteractor;
mKeyguardViewConfigurator = keyguardViewConfigurator;
@@ -1172,6 +1176,10 @@
collectFlow(mView, mLockscreenToOccludedTransitionViewModel.lockscreenTranslationY(
mLockscreenToOccludedTransitionTranslationY),
setTransitionY(mNotificationStackScrollLayoutController), mMainDispatcher);
+
+ // Primary bouncer->Gone (ensures lockscreen content is not visible on successful auth)
+ collectFlow(mView, mPrimaryBouncerToGoneTransitionViewModel.getLockscreenAlpha(),
+ setTransitionAlpha(mNotificationStackScrollLayoutController), mMainDispatcher);
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/TEST_MAPPING b/packages/SystemUI/src/com/android/systemui/statusbar/TEST_MAPPING
new file mode 100644
index 0000000..8849d6e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/TEST_MAPPING
@@ -0,0 +1,29 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsNotificationTestCases",
+ "options": [
+ {
+ "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ },
+ {
+ "exclude-annotation": "android.platform.test.annotations.LargeTest"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.LargeTest"
+ }
+ ]
+ }
+ ],
+ "postsubmit": [
+ {
+ "name": "CtsNotificationTestCases"
+ }
+ ]
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
index 80f5d19..a4e8c2e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
@@ -21,16 +21,12 @@
import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
import static com.android.systemui.statusbar.notification.NotificationUtils.logKey;
-import android.net.Uri;
-import android.os.UserHandle;
-import android.provider.Settings;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.annotation.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.statusbar.IStatusBarService;
@@ -75,10 +71,6 @@
@NotificationRowScope
public class ExpandableNotificationRowController implements NotifViewController {
private static final String TAG = "NotifRowController";
-
- static final Uri BUBBLES_SETTING_URI =
- Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BUBBLES);
- private static final String BUBBLES_SETTING_ENABLED_VALUE = "1";
private final ExpandableNotificationRow mView;
private final NotificationListContainer mListContainer;
private final RemoteInputViewSubcomponent.Factory mRemoteInputViewSubcomponentFactory;
@@ -112,23 +104,6 @@
private final ExpandableNotificationRowDragController mDragController;
private final NotificationDismissibilityProvider mDismissibilityProvider;
private final IStatusBarService mStatusBarService;
-
- private final NotificationSettingsController mSettingsController;
-
- @VisibleForTesting
- final NotificationSettingsController.Listener mSettingsListener =
- new NotificationSettingsController.Listener() {
- @Override
- public void onSettingChanged(Uri setting, int userId, String value) {
- if (BUBBLES_SETTING_URI.equals(setting)) {
- final int viewUserId = mView.getEntry().getSbn().getUserId();
- if (viewUserId == UserHandle.USER_ALL || viewUserId == userId) {
- mView.getPrivateLayout().setBubblesEnabledForUser(
- BUBBLES_SETTING_ENABLED_VALUE.equals(value));
- }
- }
- }
- };
private final ExpandableNotificationRow.ExpandableNotificationRowLogger mLoggerCallback =
new ExpandableNotificationRow.ExpandableNotificationRowLogger() {
@Override
@@ -226,7 +201,6 @@
FeatureFlags featureFlags,
PeopleNotificationIdentifier peopleNotificationIdentifier,
Optional<BubblesManager> bubblesManagerOptional,
- NotificationSettingsController settingsController,
ExpandableNotificationRowDragController dragController,
NotificationDismissibilityProvider dismissibilityProvider,
IStatusBarService statusBarService) {
@@ -255,7 +229,6 @@
mFeatureFlags = featureFlags;
mPeopleNotificationIdentifier = peopleNotificationIdentifier;
mBubblesManagerOptional = bubblesManagerOptional;
- mSettingsController = settingsController;
mDragController = dragController;
mMetricsLogger = metricsLogger;
mChildrenContainerLogger = childrenContainerLogger;
@@ -325,14 +298,12 @@
NotificationMenuRowPlugin.class, false /* Allow multiple */);
mView.setOnKeyguard(mStatusBarStateController.getState() == KEYGUARD);
mStatusBarStateController.addCallback(mStatusBarStateListener);
- mSettingsController.addCallback(BUBBLES_SETTING_URI, mSettingsListener);
}
@Override
public void onViewDetachedFromWindow(View v) {
mPluginManager.removePluginListener(mView);
mStatusBarStateController.removeCallback(mStatusBarStateListener);
- mSettingsController.removeCallback(BUBBLES_SETTING_URI, mSettingsListener);
}
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 1657c28..0322573 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -44,7 +44,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.R;
-import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.SmartReplyController;
@@ -66,6 +65,7 @@
import com.android.systemui.statusbar.policy.SmartReplyView;
import com.android.systemui.statusbar.policy.dagger.RemoteInputViewSubcomponent;
import com.android.systemui.util.Compile;
+import com.android.systemui.wmshell.BubblesManager;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -134,7 +134,6 @@
private PeopleNotificationIdentifier mPeopleIdentifier;
private RemoteInputViewSubcomponent.Factory mRemoteInputSubcomponentFactory;
private IStatusBarService mStatusBarService;
- private boolean mBubblesEnabledForUser;
/**
* List of listeners for when content views become inactive (i.e. not the showing view).
@@ -1441,17 +1440,12 @@
}
}
- @Background
- public void setBubblesEnabledForUser(boolean enabled) {
- mBubblesEnabledForUser = enabled;
- }
-
@VisibleForTesting
boolean shouldShowBubbleButton(NotificationEntry entry) {
boolean isPersonWithShortcut =
mPeopleIdentifier.getPeopleNotificationType(entry)
>= PeopleNotificationIdentifier.TYPE_FULL_PERSON;
- return mBubblesEnabledForUser
+ return BubblesManager.areBubblesEnabled(mContext, entry.getSbn().getUser())
&& isPersonWithShortcut
&& entry.getBubbleMetadata() != null;
}
@@ -2085,7 +2079,6 @@
pw.print("null");
}
pw.println();
- pw.println("mBubblesEnabledForUser: " + mBubblesEnabledForUser);
pw.print("RemoteInputViews { ");
pw.print(" visibleType: " + mVisibleType);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSettingsController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSettingsController.java
deleted file mode 100644
index 585ff52..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSettingsController.java
+++ /dev/null
@@ -1,167 +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.statusbar.notification.row;
-
-import android.content.Context;
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.HandlerExecutor;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.systemui.Dumpable;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.qualifiers.Background;
-import com.android.systemui.dump.DumpManager;
-import com.android.systemui.settings.UserTracker;
-import com.android.systemui.util.settings.SecureSettings;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.HashMap;
-
-import javax.inject.Inject;
-
-/**
- * Centralized controller for listening to Secure Settings changes and informing in-process
- * listeners, on a background thread.
- */
-@SysUISingleton
-public class NotificationSettingsController implements Dumpable {
-
- private final static String TAG = "NotificationSettingsController";
- private final UserTracker mUserTracker;
- private final UserTracker.Callback mCurrentUserTrackerCallback;
- private final Handler mHandler;
- private final ContentObserver mContentObserver;
- private final SecureSettings mSecureSettings;
- private final HashMap<Uri, ArrayList<Listener>> mListeners = new HashMap<>();
-
- @Inject
- public NotificationSettingsController(UserTracker userTracker,
- @Background Handler handler,
- SecureSettings secureSettings,
- DumpManager dumpManager) {
- mUserTracker = userTracker;
- mHandler = handler;
- mSecureSettings = secureSettings;
- mContentObserver = new ContentObserver(mHandler) {
- @Override
- public void onChange(boolean selfChange, Uri uri) {
- super.onChange(selfChange, uri);
- synchronized (mListeners) {
- if (mListeners.containsKey(uri)) {
- for (Listener listener : mListeners.get(uri)) {
- notifyListener(listener, uri);
- }
- }
- }
- }
- };
-
- mCurrentUserTrackerCallback = new UserTracker.Callback() {
- @Override
- public void onUserChanged(int newUser, Context userContext) {
- synchronized (mListeners) {
- if (mListeners.size() > 0) {
- mSecureSettings.unregisterContentObserver(mContentObserver);
- for (Uri uri : mListeners.keySet()) {
- mSecureSettings.registerContentObserverForUser(
- uri, false, mContentObserver, newUser);
- }
- }
- }
- }
- };
- mUserTracker.addCallback(mCurrentUserTrackerCallback, new HandlerExecutor(handler));
-
- dumpManager.registerNormalDumpable(TAG, this);
- }
-
- /**
- * Register callback whenever the given secure settings changes.
- *
- * On registration, will call back on the provided handler with the current value of
- * the setting.
- */
- public void addCallback(@NonNull Uri uri, @NonNull Listener listener) {
- if (uri == null || listener == null) {
- return;
- }
- synchronized (mListeners) {
- ArrayList<Listener> currentListeners = mListeners.get(uri);
- if (currentListeners == null) {
- currentListeners = new ArrayList<>();
- }
- if (!currentListeners.contains(listener)) {
- currentListeners.add(listener);
- }
- mListeners.put(uri, currentListeners);
- if (currentListeners.size() == 1) {
- mSecureSettings.registerContentObserverForUser(
- uri, false, mContentObserver, mUserTracker.getUserId());
- }
- }
- mHandler.post(() -> notifyListener(listener, uri));
-
- }
-
- public void removeCallback(Uri uri, Listener listener) {
- synchronized (mListeners) {
- ArrayList<Listener> currentListeners = mListeners.get(uri);
-
- if (currentListeners != null) {
- currentListeners.remove(listener);
- }
- if (currentListeners == null || currentListeners.size() == 0) {
- mListeners.remove(uri);
- }
-
- if (mListeners.size() == 0) {
- mSecureSettings.unregisterContentObserver(mContentObserver);
- }
- }
- }
-
- @Override
- public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
- synchronized (mListeners) {
- pw.println("Settings Uri Listener List:");
- for (Uri uri : mListeners.keySet()) {
- pw.println(" Uri=" + uri);
- for (Listener listener : mListeners.get(uri)) {
- pw.println(" Listener=" + listener.getClass().getName());
- }
- }
- }
- }
-
- private void notifyListener(Listener listener, Uri uri) {
- final String setting = uri == null ? null : uri.getLastPathSegment();
- int userId = mUserTracker.getUserId();
- listener.onSettingChanged(uri, userId, mSecureSettings.getStringForUser(setting, userId));
- }
-
- /**
- * Listener invoked whenever settings are changed.
- */
- public interface Listener {
- void onSettingChanged(@NonNull Uri setting, int userId, @Nullable String value);
- }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
index 1227287..2affb817 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
@@ -150,10 +150,10 @@
fun onTouch(event: MotionEvent) {
if (centralSurfaces.statusBarWindowState == WINDOW_STATE_SHOWING) {
val upOrCancel =
- event.action == MotionEvent.ACTION_UP ||
+ event.action == MotionEvent.ACTION_UP ||
event.action == MotionEvent.ACTION_CANCEL
centralSurfaces.setInteracting(WINDOW_STATUS_BAR,
- !upOrCancel || shadeController.isExpandedVisible)
+ !upOrCancel || shadeController.isExpandedVisible)
}
}
@@ -171,7 +171,7 @@
if (!centralSurfaces.commandQueuePanelsEnabled) {
if (event.action == MotionEvent.ACTION_DOWN) {
Log.v(TAG, String.format("onTouchForwardedFromStatusBar: panel disabled, " +
- "ignoring touch at (${event.x.toInt()},${event.y.toInt()})"))
+ "ignoring touch at (${event.x.toInt()},${event.y.toInt()})"))
}
return false
}
@@ -182,7 +182,7 @@
sceneInteractor.get()
.onRemoteUserInput(RemoteUserInput.translateMotionEvent(event))
// TODO(b/291965119): remove once view is expanded to cover the status bar
- sceneInteractor.get().setVisible(true)
+ sceneInteractor.get().setVisible(true, "swipe down from status bar")
return false
}
@@ -191,11 +191,11 @@
// bar eat the gesture.
if (!shadeViewController.isViewEnabled) {
shadeLogger.logMotionEvent(event,
- "onTouchForwardedFromStatusBar: panel view disabled")
+ "onTouchForwardedFromStatusBar: panel view disabled")
return true
}
if (shadeViewController.isFullyCollapsed &&
- event.y < 1f) {
+ event.y < 1f) {
// b/235889526 Eat events on the top edge of the phone when collapsed
shadeLogger.logMotionEvent(event, "top edge touch ignored")
return true
@@ -257,27 +257,27 @@
view: PhoneStatusBarView
): PhoneStatusBarViewController {
val statusBarMoveFromCenterAnimationController =
- if (featureFlags.isEnabled(Flags.ENABLE_UNFOLD_STATUS_BAR_ANIMATIONS)) {
- unfoldComponent.getOrNull()?.getStatusBarMoveFromCenterAnimationController()
- } else {
- null
- }
+ if (featureFlags.isEnabled(Flags.ENABLE_UNFOLD_STATUS_BAR_ANIMATIONS)) {
+ unfoldComponent.getOrNull()?.getStatusBarMoveFromCenterAnimationController()
+ } else {
+ null
+ }
return PhoneStatusBarViewController(
- view,
- progressProvider.getOrNull(),
- centralSurfaces,
- shadeController,
- shadeViewController,
- sceneInteractor,
- shadeLogger,
- statusBarMoveFromCenterAnimationController,
- userChipViewModel,
- viewUtil,
- featureFlags,
- configurationController,
- statusOverlayHoverListenerFactory,
+ view,
+ progressProvider.getOrNull(),
+ centralSurfaces,
+ shadeController,
+ shadeViewController,
+ sceneInteractor,
+ shadeLogger,
+ statusBarMoveFromCenterAnimationController,
+ userChipViewModel,
+ viewUtil,
+ featureFlags,
+ configurationController,
+ statusOverlayHoverListenerFactory,
)
}
}
-}
+}
\ No newline at end of file
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 f4c5723..cffc833 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
@@ -38,6 +38,19 @@
constructor(
@VerboseMobileViewLog private val buffer: LogBuffer,
) {
+ fun logBinderReceivedVisibility(parentView: View, subId: Int, visibility: Boolean) {
+ buffer.log(
+ TAG,
+ LogLevel.VERBOSE,
+ {
+ str1 = parentView.getIdForLogging()
+ int1 = subId
+ bool1 = visibility
+ },
+ { "Binder[subId=$int1, viewId=$str1] received visibility: $bool1" },
+ )
+ }
+
fun logBinderReceivedSignalIcon(parentView: View, subId: Int, icon: SignalIconModel) {
buffer.log(
TAG,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt
index c221109..55bc8d5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt
@@ -99,7 +99,16 @@
}
}
- launch { viewModel.isVisible.collect { isVisible -> view.isVisible = isVisible } }
+ launch {
+ viewModel.isVisible.collect { isVisible ->
+ viewModel.verboseLogger?.logBinderReceivedVisibility(
+ view,
+ viewModel.subscriptionId,
+ isVisible
+ )
+ view.isVisible = isVisible
+ }
+ }
// Set the icon for the triangle
launch {
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java b/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java
index 4da5d49..de9b5ee 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java
@@ -157,9 +157,10 @@
* Query the wallet cards from {@link QuickAccessWalletClient}.
*
* @param cardsRetriever a callback to retrieve wallet cards.
+ * @param maxCards the maximum number of cards requested from the QuickAccessWallet
*/
public void queryWalletCards(
- QuickAccessWalletClient.OnWalletCardsRetrievedCallback cardsRetriever) {
+ QuickAccessWalletClient.OnWalletCardsRetrievedCallback cardsRetriever, int maxCards) {
if (mClock.elapsedRealtime() - mQawClientCreatedTimeMillis
> RECREATION_TIME_WINDOW) {
Log.i(TAG, "Re-creating the QAW client to avoid stale.");
@@ -175,11 +176,22 @@
mContext.getResources().getDimensionPixelSize(R.dimen.wallet_tile_card_view_height);
int iconSizePx = mContext.getResources().getDimensionPixelSize(R.dimen.wallet_icon_size);
GetWalletCardsRequest request =
- new GetWalletCardsRequest(cardWidth, cardHeight, iconSizePx, /* maxCards= */ 1);
+ new GetWalletCardsRequest(cardWidth, cardHeight, iconSizePx, maxCards);
mQuickAccessWalletClient.getWalletCards(mBgExecutor, request, cardsRetriever);
}
/**
+ * Query the wallet cards from {@link QuickAccessWalletClient}.
+ *
+ * @param cardsRetriever a callback to retrieve wallet cards.
+ */
+ public void queryWalletCards(
+ QuickAccessWalletClient.OnWalletCardsRetrievedCallback cardsRetriever) {
+ queryWalletCards(cardsRetriever, /* maxCards= */ 1);
+ }
+
+
+ /**
* Re-create the {@link QuickAccessWalletClient} of the controller.
*/
public void reCreateWalletClient() {
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/controller/WalletContextualSuggestionsController.kt b/packages/SystemUI/src/com/android/systemui/wallet/controller/WalletContextualSuggestionsController.kt
index b3ad9b0..75df1bd 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/controller/WalletContextualSuggestionsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/wallet/controller/WalletContextualSuggestionsController.kt
@@ -39,7 +39,6 @@
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
@@ -88,7 +87,7 @@
QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE
)
walletController.updateWalletPreference()
- walletController.queryWalletCards(callback)
+ walletController.queryWalletCards(callback, MAX_CARDS)
awaitClose {
walletController.unregisterWalletChangeObservers(
@@ -152,5 +151,6 @@
companion object {
private const val TAG = "WalletSuggestions"
+ private const val MAX_CARDS = 50
}
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
index e447c29..efb981e 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
@@ -733,20 +733,20 @@
// is
// not enough to trigger a dismissal of the keyguard.
underTest.onViewAttached()
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer, null))
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer, null), "reason")
runCurrent()
verify(viewMediatorCallback, never()).keyguardDone(anyBoolean(), anyInt())
// While listening, going from the bouncer scene to the gone scene, does dismiss the
// keyguard.
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Gone, null))
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Gone, null), "reason")
runCurrent()
verify(viewMediatorCallback).keyguardDone(anyBoolean(), anyInt())
// While listening, moving back to the bouncer scene does not dismiss the keyguard
// again.
clearInvocations(viewMediatorCallback)
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer, null))
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer, null), "reason")
runCurrent()
verify(viewMediatorCallback, never()).keyguardDone(anyBoolean(), anyInt())
@@ -754,12 +754,12 @@
// scene
// does not dismiss the keyguard while we're not listening.
underTest.onViewDetached()
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Gone, null))
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Gone, null), "reason")
runCurrent()
verify(viewMediatorCallback, never()).keyguardDone(anyBoolean(), anyInt())
// While not listening, moving back to the bouncer does not dismiss the keyguard.
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer, null))
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer, null), "reason")
runCurrent()
verify(viewMediatorCallback, never()).keyguardDone(anyBoolean(), anyInt())
@@ -767,7 +767,7 @@
// gone
// scene now does dismiss the keyguard again.
underTest.onViewAttached()
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Gone, null))
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Gone, null), "reason")
runCurrent()
verify(viewMediatorCallback).keyguardDone(anyBoolean(), anyInt())
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricNotificationServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricNotificationServiceTest.java
index b8bca3a..b0d0063 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricNotificationServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricNotificationServiceTest.java
@@ -23,6 +23,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -75,6 +76,7 @@
private TestableLooper mLooper;
private KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback;
private KeyguardStateController.Callback mKeyguardStateControllerCallback;
+ private BiometricNotificationService mBiometricNotificationService;
@Before
public void setUp() {
@@ -83,12 +85,10 @@
BiometricNotificationDialogFactory dialogFactory = new BiometricNotificationDialogFactory();
BiometricNotificationBroadcastReceiver broadcastReceiver =
new BiometricNotificationBroadcastReceiver(mContext, dialogFactory);
- BiometricNotificationService biometricNotificationService =
- new BiometricNotificationService(mContext,
- mKeyguardUpdateMonitor, mKeyguardStateController, handler,
- mNotificationManager,
- broadcastReceiver);
- biometricNotificationService.start();
+ mBiometricNotificationService = new BiometricNotificationService(mContext,
+ mKeyguardUpdateMonitor, mKeyguardStateController, handler,
+ mNotificationManager, broadcastReceiver);
+ mBiometricNotificationService.start();
ArgumentCaptor<KeyguardUpdateMonitorCallback> updateMonitorCallbackArgumentCaptor =
ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback.class);
@@ -149,4 +149,23 @@
.isEqualTo(ACTION_SHOW_FACE_REENROLL_DIALOG);
}
+ @Test
+ public void testResetFaceUnlockReEnroll_onStart() {
+ when(mKeyguardStateController.isShowing()).thenReturn(false);
+
+ mKeyguardUpdateMonitorCallback.onBiometricError(
+ BiometricFaceConstants.BIOMETRIC_ERROR_RE_ENROLL,
+ "Testing Face Re-enrollment" /* errString */,
+ BiometricSourceType.FACE
+ );
+
+ mBiometricNotificationService.start();
+ mKeyguardStateControllerCallback.onKeyguardShowingChanged();
+
+ mLooper.moveTimeForward(SHOW_NOTIFICATION_DELAY_MS);
+ mLooper.processAllMessages();
+
+ verify(mNotificationManager, never()).notifyAsUser(eq(TAG), eq(FACE_NOTIFICATION_ID),
+ mNotificationArgumentCaptor.capture(), any());
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactoryTest.kt
index 992ee1a..efae3fe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactoryTest.kt
@@ -59,63 +59,79 @@
}
@Test
- fun bouncerMessages_choosesTheRightMessage_basedOnSecurityModeAndFpAllowedInBouncer() =
+ fun bouncerMessages_choosesTheRightMessage_basedOnSecurityModeAndFpAuthIsAllowed() =
testScope.runTest {
- primaryMessage(PROMPT_REASON_DEFAULT, mode = PIN, fpAllowedInBouncer = false)
+ primaryMessage(PROMPT_REASON_DEFAULT, mode = PIN, fpAuthAllowed = false)
.isEqualTo("Enter PIN")
- primaryMessage(PROMPT_REASON_DEFAULT, mode = PIN, fpAllowedInBouncer = true)
+ primaryMessage(PROMPT_REASON_DEFAULT, mode = PIN, fpAuthAllowed = true)
.isEqualTo("Unlock with PIN or fingerprint")
- primaryMessage(PROMPT_REASON_DEFAULT, mode = Password, fpAllowedInBouncer = false)
+ primaryMessage(PROMPT_REASON_DEFAULT, mode = Password, fpAuthAllowed = false)
.isEqualTo("Enter password")
- primaryMessage(PROMPT_REASON_DEFAULT, mode = Password, fpAllowedInBouncer = true)
+ primaryMessage(PROMPT_REASON_DEFAULT, mode = Password, fpAuthAllowed = true)
.isEqualTo("Unlock with password or fingerprint")
- primaryMessage(PROMPT_REASON_DEFAULT, mode = Pattern, fpAllowedInBouncer = false)
+ primaryMessage(PROMPT_REASON_DEFAULT, mode = Pattern, fpAuthAllowed = false)
.isEqualTo("Draw pattern")
- primaryMessage(PROMPT_REASON_DEFAULT, mode = Pattern, fpAllowedInBouncer = true)
+ primaryMessage(PROMPT_REASON_DEFAULT, mode = Pattern, fpAuthAllowed = true)
.isEqualTo("Unlock with pattern or fingerprint")
}
@Test
- fun bouncerMessages_setsPrimaryAndSecondaryMessage_basedOnSecurityModeAndFpAllowedInBouncer() =
+ fun bouncerMessages_overridesSecondaryMessageValue() =
+ testScope.runTest {
+ val bouncerMessageModel =
+ bouncerMessageModel(
+ PIN,
+ true,
+ PROMPT_REASON_DEFAULT,
+ secondaryMessageOverride = "face acquisition message"
+ )!!
+ assertThat(context.resources.getString(bouncerMessageModel.message!!.messageResId!!))
+ .isEqualTo("Unlock with PIN or fingerprint")
+ assertThat(bouncerMessageModel.secondaryMessage!!.message!!)
+ .isEqualTo("face acquisition message")
+ }
+
+ @Test
+ fun bouncerMessages_setsPrimaryAndSecondaryMessage_basedOnSecurityModeAndFpAuthIsAllowed() =
testScope.runTest {
primaryMessage(
PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT,
mode = PIN,
- fpAllowedInBouncer = true
+ fpAuthAllowed = true
)
.isEqualTo("Wrong PIN. Try again.")
secondaryMessage(
PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT,
mode = PIN,
- fpAllowedInBouncer = true
+ fpAuthAllowed = true
)
.isEqualTo("Or unlock with fingerprint")
primaryMessage(
PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT,
mode = Password,
- fpAllowedInBouncer = true
+ fpAuthAllowed = true
)
.isEqualTo("Wrong password. Try again.")
secondaryMessage(
PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT,
mode = Password,
- fpAllowedInBouncer = true
+ fpAuthAllowed = true
)
.isEqualTo("Or unlock with fingerprint")
primaryMessage(
PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT,
mode = Pattern,
- fpAllowedInBouncer = true
+ fpAuthAllowed = true
)
.isEqualTo("Wrong pattern. Try again.")
secondaryMessage(
PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT,
mode = Pattern,
- fpAllowedInBouncer = true
+ fpAuthAllowed = true
)
.isEqualTo("Or unlock with fingerprint")
}
@@ -123,11 +139,11 @@
private fun primaryMessage(
reason: Int,
mode: KeyguardSecurityModel.SecurityMode,
- fpAllowedInBouncer: Boolean
+ fpAuthAllowed: Boolean
): StringSubject {
return assertThat(
context.resources.getString(
- bouncerMessageModel(mode, fpAllowedInBouncer, reason)!!.message!!.messageResId!!
+ bouncerMessageModel(mode, fpAuthAllowed, reason)!!.message!!.messageResId!!
)
)!!
}
@@ -135,25 +151,28 @@
private fun secondaryMessage(
reason: Int,
mode: KeyguardSecurityModel.SecurityMode,
- fpAllowedInBouncer: Boolean
+ fpAuthAllowed: Boolean
): StringSubject {
return assertThat(
context.resources.getString(
- bouncerMessageModel(mode, fpAllowedInBouncer, reason)!!
- .secondaryMessage!!
- .messageResId!!
+ bouncerMessageModel(mode, fpAuthAllowed, reason)!!.secondaryMessage!!.messageResId!!
)
)!!
}
private fun bouncerMessageModel(
mode: KeyguardSecurityModel.SecurityMode,
- fpAllowedInBouncer: Boolean,
- reason: Int
+ fpAuthAllowed: Boolean,
+ reason: Int,
+ secondaryMessageOverride: String? = null,
): BouncerMessageModel? {
whenever(securityModel.getSecurityMode(0)).thenReturn(mode)
- whenever(updateMonitor.isFingerprintAllowedInBouncer).thenReturn(fpAllowedInBouncer)
+ whenever(updateMonitor.isUnlockingWithFingerprintAllowed).thenReturn(fpAuthAllowed)
- return underTest.createFromPromptReason(reason, 0)
+ return underTest.createFromPromptReason(
+ reason,
+ 0,
+ secondaryMsgOverride = secondaryMessageOverride
+ )
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/repo/BouncerMessageRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/repo/BouncerMessageRepositoryTest.kt
index de712da..2be7d8a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/repo/BouncerMessageRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/repo/BouncerMessageRepositoryTest.kt
@@ -51,6 +51,7 @@
import com.android.systemui.bouncer.shared.model.BouncerMessageModel
import com.android.systemui.bouncer.shared.model.Message
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.flags.SystemPropertiesHelper
import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
import com.android.systemui.keyguard.data.repository.FakeTrustRepository
@@ -79,6 +80,7 @@
@Mock private lateinit var updateMonitor: KeyguardUpdateMonitor
@Mock private lateinit var securityModel: KeyguardSecurityModel
+ @Mock private lateinit var systemPropertiesHelper: SystemPropertiesHelper
@Captor
private lateinit var updateMonitorCallback: ArgumentCaptor<KeyguardUpdateMonitorCallback>
@@ -99,7 +101,7 @@
fingerprintRepository = FakeDeviceEntryFingerprintAuthRepository()
testScope = TestScope()
- whenever(updateMonitor.isFingerprintAllowedInBouncer).thenReturn(false)
+ whenever(updateMonitor.isUnlockingWithFingerprintAllowed).thenReturn(false)
whenever(securityModel.getSecurityMode(PRIMARY_USER_ID)).thenReturn(PIN)
underTest =
BouncerMessageRepositoryImpl(
@@ -108,7 +110,8 @@
updateMonitor = updateMonitor,
bouncerMessageFactory = BouncerMessageFactory(updateMonitor, securityModel),
userRepository = userRepository,
- fingerprintAuthRepository = fingerprintRepository
+ fingerprintAuthRepository = fingerprintRepository,
+ systemPropertiesHelper = systemPropertiesHelper
)
}
@@ -214,6 +217,21 @@
}
@Test
+ fun onRestartForMainlineUpdate_shouldProvideRelevantMessage() =
+ testScope.runTest {
+ whenever(systemPropertiesHelper.get("sys.boot.reason.last"))
+ .thenReturn("reboot,mainline_update")
+ userRepository.setSelectedUserInfo(PRIMARY_USER)
+ biometricSettingsRepository.setFaceEnrolled(true)
+ biometricSettingsRepository.setIsFaceAuthEnabled(true)
+
+ verifyMessagesForAuthFlag(
+ STRONG_AUTH_REQUIRED_AFTER_BOOT to
+ Pair(keyguard_enter_pin, R.string.kg_prompt_after_update_pin),
+ )
+ }
+
+ @Test
fun onAuthFlagsChanged_withTrustNotManagedAndNoBiometrics_isANoop() =
testScope.runTest {
userRepository.setSelectedUserInfo(PRIMARY_USER)
@@ -345,8 +363,8 @@
private fun message(primaryResId: Int, secondaryResId: Int): BouncerMessageModel {
return BouncerMessageModel(
- message = Message(messageResId = primaryResId),
- secondaryMessage = Message(messageResId = secondaryResId)
+ message = Message(messageResId = primaryResId, animate = false),
+ secondaryMessage = Message(messageResId = secondaryResId, animate = false)
)
}
private fun message(value: String): BouncerMessageModel {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractorTest.kt
index 8e5256e..3ca94aa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractorTest.kt
@@ -76,7 +76,7 @@
allowTestableLooperAsMainThread()
whenever(securityModel.getSecurityMode(PRIMARY_USER_ID)).thenReturn(PIN)
- whenever(updateMonitor.isFingerprintAllowedInBouncer).thenReturn(false)
+ whenever(updateMonitor.isUnlockingWithFingerprintAllowed).thenReturn(false)
}
suspend fun TestScope.init() {
@@ -150,11 +150,12 @@
underTest.setCustomMessage("not empty")
- assertThat(repository.customMessage.value)
- .isEqualTo(BouncerMessageModel(secondaryMessage = Message(message = "not empty")))
+ val customMessage = repository.customMessage
+ assertThat(customMessage.value!!.message!!.messageResId).isEqualTo(keyguard_enter_pin)
+ assertThat(customMessage.value!!.secondaryMessage!!.message).isEqualTo("not empty")
underTest.setCustomMessage(null)
- assertThat(repository.customMessage.value).isNull()
+ assertThat(customMessage.value).isNull()
}
@Test
@@ -164,11 +165,15 @@
underTest.setFaceAcquisitionMessage("not empty")
- assertThat(repository.faceAcquisitionMessage.value)
- .isEqualTo(BouncerMessageModel(secondaryMessage = Message(message = "not empty")))
+ val faceAcquisitionMessage = repository.faceAcquisitionMessage
+
+ assertThat(faceAcquisitionMessage.value!!.message!!.messageResId)
+ .isEqualTo(keyguard_enter_pin)
+ assertThat(faceAcquisitionMessage.value!!.secondaryMessage!!.message)
+ .isEqualTo("not empty")
underTest.setFaceAcquisitionMessage(null)
- assertThat(repository.faceAcquisitionMessage.value).isNull()
+ assertThat(faceAcquisitionMessage.value).isNull()
}
@Test
@@ -178,11 +183,15 @@
underTest.setFingerprintAcquisitionMessage("not empty")
- assertThat(repository.fingerprintAcquisitionMessage.value)
- .isEqualTo(BouncerMessageModel(secondaryMessage = Message(message = "not empty")))
+ val fingerprintAcquisitionMessage = repository.fingerprintAcquisitionMessage
+
+ assertThat(fingerprintAcquisitionMessage.value!!.message!!.messageResId)
+ .isEqualTo(keyguard_enter_pin)
+ assertThat(fingerprintAcquisitionMessage.value!!.secondaryMessage!!.message)
+ .isEqualTo("not empty")
underTest.setFingerprintAcquisitionMessage(null)
- assertThat(repository.fingerprintAcquisitionMessage.value).isNull()
+ assertThat(fingerprintAcquisitionMessage.value).isNull()
}
@Test
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 1f089ca..7f8d54c 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
@@ -79,7 +79,7 @@
AuthenticationMethodModel.Password
)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer))
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
@@ -99,7 +99,7 @@
AuthenticationMethodModel.Password
)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer))
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
runCurrent()
@@ -119,7 +119,7 @@
AuthenticationMethodModel.Password
)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer))
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onPasswordInputChanged("password")
@@ -139,7 +139,7 @@
AuthenticationMethodModel.Password
)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer))
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onPasswordInputChanged("wrong")
@@ -161,7 +161,7 @@
AuthenticationMethodModel.Password
)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer))
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onPasswordInputChanged("wrong")
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 af54989..57fcbe5 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
@@ -83,7 +83,7 @@
AuthenticationMethodModel.Pattern
)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer))
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
@@ -105,7 +105,7 @@
AuthenticationMethodModel.Pattern
)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer))
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
runCurrent()
@@ -128,7 +128,7 @@
AuthenticationMethodModel.Pattern
)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer))
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onDragStart()
@@ -176,7 +176,7 @@
AuthenticationMethodModel.Pattern
)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer))
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onDragStart()
@@ -208,7 +208,7 @@
AuthenticationMethodModel.Pattern
)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer))
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onDragStart()
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 c12ed03..81c68ed 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
@@ -79,7 +79,7 @@
val message by collectLastValue(bouncerViewModel.message)
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer))
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
@@ -97,7 +97,7 @@
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer))
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
runCurrent()
@@ -117,7 +117,7 @@
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer))
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
runCurrent()
@@ -138,7 +138,7 @@
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer))
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
@@ -161,7 +161,7 @@
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer))
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
runCurrent()
@@ -183,7 +183,7 @@
val currentScene by collectLastValue(sceneInteractor.currentScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer))
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
FakeAuthenticationRepository.DEFAULT_PIN.forEach { digit ->
@@ -203,7 +203,7 @@
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer))
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onPinButtonClicked(1)
@@ -227,7 +227,7 @@
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer))
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onPinButtonClicked(1)
@@ -258,7 +258,7 @@
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
utils.authenticationRepository.setAutoConfirmEnabled(true)
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer))
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
FakeAuthenticationRepository.DEFAULT_PIN.forEach { digit ->
@@ -277,7 +277,7 @@
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
utils.authenticationRepository.setAutoConfirmEnabled(true)
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer))
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
FakeAuthenticationRepository.DEFAULT_PIN.dropLast(1).forEach { digit ->
diff --git a/packages/SystemUI/tests/src/com/android/systemui/complication/DreamClockTimeComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/complication/DreamClockTimeComplicationTest.java
index 57d3a01..cbbbe52 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/complication/DreamClockTimeComplicationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/complication/DreamClockTimeComplicationTest.java
@@ -28,7 +28,9 @@
import androidx.test.filters.SmallTest;
+import com.android.internal.logging.UiEventLogger;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.complication.dagger.DreamClockTimeComplicationComponent;
import com.android.systemui.condition.SelfExecutingMonitor;
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.shared.condition.Monitor;
@@ -36,11 +38,10 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import javax.inject.Provider;
-
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class DreamClockTimeComplicationTest extends SysuiTestCase {
@@ -55,8 +56,10 @@
private DreamClockTimeComplication mComplication;
@Mock
- private Provider<DreamClockTimeComplication.DreamClockTimeViewHolder>
- mDreamClockTimeViewHolderProvider;
+ private DreamClockTimeComplicationComponent.Factory mComponentFactory;
+
+ @Mock
+ private DreamClockTimeComplicationComponent mComponent;
@Mock
private DreamClockTimeComplication.DreamClockTimeViewHolder
@@ -71,12 +74,19 @@
@Mock
private ComplicationLayoutParams mLayoutParams;
+ @Mock
+ private DreamClockTimeComplication.DreamClockTimeViewController mViewController;
+
+ @Mock
+ private UiEventLogger mUiEventLogger;
+
private Monitor mMonitor;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
- when(mDreamClockTimeViewHolderProvider.get()).thenReturn(mDreamClockTimeViewHolder);
+ when(mComponentFactory.create()).thenReturn(mComponent);
+ when(mComponent.getViewHolder()).thenReturn(mDreamClockTimeViewHolder);
mMonitor = SelfExecutingMonitor.createInstance();
}
@@ -100,21 +110,21 @@
@Test
public void testComplicationRequiredTypeAvailability() {
final DreamClockTimeComplication complication =
- new DreamClockTimeComplication(mDreamClockTimeViewHolderProvider);
+ new DreamClockTimeComplication(mComponentFactory);
assertEquals(Complication.COMPLICATION_TYPE_TIME,
complication.getRequiredTypeAvailability());
}
/**
* Verifies {@link DreamClockTimeComplication.DreamClockTimeViewHolder} is obtainable from its
- * provider when the complication creates view.
+ * component when the complication creates view.
*/
@Test
- public void testComplicationViewHolderProviderOnCreateView() {
+ public void testComplicationViewHolderComponentOnCreateView() {
final DreamClockTimeComplication complication =
- new DreamClockTimeComplication(mDreamClockTimeViewHolderProvider);
+ new DreamClockTimeComplication(mComponentFactory);
final Complication.ViewHolder viewHolder = complication.createView(mComplicationViewModel);
- verify(mDreamClockTimeViewHolderProvider).get();
+ verify(mComponent).getViewHolder();
assertThat(viewHolder).isEqualTo(mDreamClockTimeViewHolder);
}
@@ -125,8 +135,23 @@
@Test
public void testComplicationViewHolderContentAccessors() {
final DreamClockTimeComplication.DreamClockTimeViewHolder viewHolder =
- new DreamClockTimeComplication.DreamClockTimeViewHolder(mView, mLayoutParams);
+ new DreamClockTimeComplication.DreamClockTimeViewHolder(mView, mLayoutParams,
+ mViewController);
assertThat(viewHolder.getView()).isEqualTo(mView);
assertThat(viewHolder.getLayoutParams()).isEqualTo(mLayoutParams);
}
+
+ @Test
+ public void testClick_logUiEvent() {
+ final DreamClockTimeComplication.DreamClockTimeViewController controller =
+ new DreamClockTimeComplication.DreamClockTimeViewController(mView, mUiEventLogger);
+ controller.onViewAttached();
+
+ final ArgumentCaptor<View.OnClickListener> clickListenerCaptor =
+ ArgumentCaptor.forClass(View.OnClickListener.class);
+ verify(mView).setOnClickListener(clickListenerCaptor.capture());
+
+ clickListenerCaptor.getValue().onClick(mView);
+ verify(mUiEventLogger).log(DreamOverlayUiEvent.DREAM_CLOCK_TAPPED);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/complication/DreamHomeControlsComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/complication/DreamHomeControlsComplicationTest.java
index 63b0b25..2207180 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/complication/DreamHomeControlsComplicationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/complication/DreamHomeControlsComplicationTest.java
@@ -234,9 +234,7 @@
verify(mHomeControlsView).setOnClickListener(clickListenerCaptor.capture());
clickListenerCaptor.getValue().onClick(mHomeControlsView);
- verify(mUiEventLogger).log(
- DreamHomeControlsComplication.DreamHomeControlsChipViewController
- .DreamOverlayEvent.DREAM_HOME_CONTROLS_TAPPED);
+ verify(mUiEventLogger).log(DreamOverlayUiEvent.DREAM_HOME_CONTROLS_TAPPED);
}
private void setHaveFavorites(boolean value) {
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 a341ca3..8a1b094 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dump/LogBufferHelper.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/dump/LogBufferHelper.kt
@@ -23,6 +23,7 @@
/**
* Creates a LogBuffer that will echo everything to logcat, which is useful for debugging tests.
*/
+@JvmOverloads
fun logcatLogBuffer(name: String = "EchoToLogcatLogBuffer") =
LogBuffer(name, 50, LogcatEchoTrackerAlways())
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 d825c2a..86e56bf 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
@@ -130,11 +130,11 @@
fun switchFromLockScreenToGone_authMethodNotSwipe_doesNotUnlockDevice() =
testScope.runTest {
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Lockscreen))
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Lockscreen), "reason")
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
assertThat(isUnlocked).isFalse()
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Gone))
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Gone), "reason")
assertThat(isUnlocked).isFalse()
}
@@ -144,13 +144,13 @@
testScope.runTest {
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
runCurrent()
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Shade))
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Shade), "reason")
runCurrent()
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
runCurrent()
assertThat(isUnlocked).isFalse()
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Gone))
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Gone), "reason")
assertThat(isUnlocked).isFalse()
}
@@ -161,7 +161,7 @@
val currentScene by collectLastValue(sceneInteractor.currentScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
runCurrent()
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.QuickSettings))
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.QuickSettings), "reason")
runCurrent()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.QuickSettings))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
index d8c78eb..904662e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
@@ -21,6 +21,7 @@
import com.android.systemui.RoboPilotTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
+import com.android.systemui.coroutines.collectValues
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
import com.android.systemui.keyguard.shared.model.KeyguardState
@@ -31,8 +32,6 @@
import com.android.systemui.util.mockito.whenever
import com.google.common.collect.Range
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
@@ -75,9 +74,7 @@
@Test
fun bouncerAlpha() =
runTest(UnconfinedTestDispatcher()) {
- val values = mutableListOf<Float>()
-
- val job = underTest.bouncerAlpha.onEach { values.add(it) }.launchIn(this)
+ val values by collectValues(underTest.bouncerAlpha)
repository.sendTransitionStep(step(0f, TransitionState.STARTED))
repository.sendTransitionStep(step(0.3f))
@@ -85,16 +82,12 @@
assertThat(values.size).isEqualTo(3)
values.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) }
-
- job.cancel()
}
@Test
fun bouncerAlpha_runDimissFromKeyguard() =
runTest(UnconfinedTestDispatcher()) {
- val values = mutableListOf<Float>()
-
- val job = underTest.bouncerAlpha.onEach { values.add(it) }.launchIn(this)
+ val values by collectValues(underTest.bouncerAlpha)
whenever(primaryBouncerInteractor.willRunDismissFromKeyguard()).thenReturn(true)
@@ -104,16 +97,52 @@
assertThat(values.size).isEqualTo(3)
values.forEach { assertThat(it).isEqualTo(0f) }
+ }
- job.cancel()
+ @Test
+ fun lockscreenAlpha() =
+ runTest(UnconfinedTestDispatcher()) {
+ val values by collectValues(underTest.lockscreenAlpha)
+
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ repository.sendTransitionStep(step(1f))
+
+ assertThat(values.size).isEqualTo(2)
+ values.forEach { assertThat(it).isEqualTo(0f) }
+ }
+
+ @Test
+ fun lockscreenAlpha_runDimissFromKeyguard() =
+ runTest(UnconfinedTestDispatcher()) {
+ val values by collectValues(underTest.lockscreenAlpha)
+
+ whenever(primaryBouncerInteractor.willRunDismissFromKeyguard()).thenReturn(true)
+
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ repository.sendTransitionStep(step(1f))
+
+ assertThat(values.size).isEqualTo(2)
+ values.forEach { assertThat(it).isEqualTo(1f) }
+ }
+
+ @Test
+ fun lockscreenAlpha_leaveShadeOpen() =
+ runTest(UnconfinedTestDispatcher()) {
+ val values by collectValues(underTest.lockscreenAlpha)
+
+ whenever(statusBarStateController.leaveOpenOnKeyguardHide()).thenReturn(true)
+
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ repository.sendTransitionStep(step(1f))
+
+ assertThat(values.size).isEqualTo(2)
+ values.forEach { assertThat(it).isEqualTo(1f) }
}
@Test
fun scrimAlpha_runDimissFromKeyguard() =
runTest(UnconfinedTestDispatcher()) {
- val values = mutableListOf<ScrimAlpha>()
-
- val job = underTest.scrimAlpha.onEach { values.add(it) }.launchIn(this)
+ val values by collectValues(underTest.scrimAlpha)
whenever(primaryBouncerInteractor.willRunDismissFromKeyguard()).thenReturn(true)
@@ -124,16 +153,12 @@
assertThat(values.size).isEqualTo(4)
values.forEach { assertThat(it).isEqualTo(ScrimAlpha()) }
-
- job.cancel()
}
@Test
fun scrimBehindAlpha_leaveShadeOpen() =
runTest(UnconfinedTestDispatcher()) {
- val values = mutableListOf<ScrimAlpha>()
-
- val job = underTest.scrimAlpha.onEach { values.add(it) }.launchIn(this)
+ val values by collectValues(underTest.scrimAlpha)
whenever(statusBarStateController.leaveOpenOnKeyguardHide()).thenReturn(true)
@@ -146,16 +171,12 @@
values.forEach {
assertThat(it).isEqualTo(ScrimAlpha(notificationsAlpha = 1f, behindAlpha = 1f))
}
-
- job.cancel()
}
@Test
fun scrimBehindAlpha_doNotLeaveShadeOpen() =
runTest(UnconfinedTestDispatcher()) {
- val values = mutableListOf<ScrimAlpha>()
-
- val job = underTest.scrimAlpha.onEach { values.add(it) }.launchIn(this)
+ val values by collectValues(underTest.scrimAlpha)
whenever(statusBarStateController.leaveOpenOnKeyguardHide()).thenReturn(false)
@@ -169,8 +190,6 @@
values.forEach { assertThat(it.frontAlpha).isEqualTo(0f) }
values.forEach { assertThat(it.behindAlpha).isIn(Range.closed(0f, 1f)) }
assertThat(values[3].behindAlpha).isEqualTo(0f)
-
- job.cancel()
}
private fun step(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogTest.java
index 45e8e27..f25454c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogTest.java
@@ -98,7 +98,8 @@
private final BroadcastSender mBroadcastSender = mock(BroadcastSender.class);
private final LocalMediaManager mLocalMediaManager = mock(LocalMediaManager.class);
private final MediaDevice mBluetoothMediaDevice = mock(BluetoothMediaDevice.class);
- private final BluetoothDevice mBluetoothDevice = mock(BluetoothDevice.class);
+ private final BluetoothDevice mBluetoothFirstDevice = mock(BluetoothDevice.class);
+ private final BluetoothDevice mBluetoothSecondDevice = mock(BluetoothDevice.class);
private final CachedBluetoothDevice mCachedBluetoothDevice = mock(CachedBluetoothDevice.class);
private final CommonNotifCollection mNotifCollection = mock(CommonNotifCollection.class);
private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class);
@@ -142,20 +143,20 @@
}
@Test
- public void connectBroadcastWithActiveDevice_noBroadcastMetadata_failToAddSource() {
+ public void startBroadcastWithConnectedDevices_noBroadcastMetadata_failToAddSource() {
when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
mLocalBluetoothLeBroadcast);
when(mLocalBluetoothLeBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(null);
when(mLocalBluetoothProfileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(
mLocalBluetoothLeBroadcastAssistant);
- mMediaOutputBroadcastDialog.connectBroadcastWithActiveDevice();
+ mMediaOutputBroadcastDialog.startBroadcastWithConnectedDevices();
verify(mLocalBluetoothLeBroadcastAssistant, never()).addSource(any(), any(), anyBoolean());
}
@Test
- public void connectBroadcastWithActiveDevice_noConnectedMediaDevice_failToAddSource() {
+ public void startBroadcastWithConnectedDevices_noConnectedMediaDevice_failToAddSource() {
when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
mLocalBluetoothLeBroadcast);
when(mLocalBluetoothLeBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(
@@ -164,13 +165,13 @@
mLocalBluetoothLeBroadcastAssistant);
when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(null);
- mMediaOutputBroadcastDialog.connectBroadcastWithActiveDevice();
+ mMediaOutputBroadcastDialog.startBroadcastWithConnectedDevices();
verify(mLocalBluetoothLeBroadcastAssistant, never()).addSource(any(), any(), anyBoolean());
}
@Test
- public void connectBroadcastWithActiveDevice_hasBroadcastSource_failToAddSource() {
+ public void startBroadcastWithConnectedDevices_hasBroadcastSource_failToAddSource() {
when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
mLocalBluetoothLeBroadcast);
when(mLocalBluetoothLeBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(
@@ -180,19 +181,19 @@
when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(mBluetoothMediaDevice);
when(((BluetoothMediaDevice) mBluetoothMediaDevice).getCachedDevice())
.thenReturn(mCachedBluetoothDevice);
- when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
+ when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothFirstDevice);
List<BluetoothLeBroadcastReceiveState> sourceList = new ArrayList<>();
sourceList.add(mBluetoothLeBroadcastReceiveState);
- when(mLocalBluetoothLeBroadcastAssistant.getAllSources(mBluetoothDevice)).thenReturn(
+ when(mLocalBluetoothLeBroadcastAssistant.getAllSources(mBluetoothFirstDevice)).thenReturn(
sourceList);
- mMediaOutputBroadcastDialog.connectBroadcastWithActiveDevice();
+ mMediaOutputBroadcastDialog.startBroadcastWithConnectedDevices();
verify(mLocalBluetoothLeBroadcastAssistant, never()).addSource(any(), any(), anyBoolean());
}
@Test
- public void connectBroadcastWithActiveDevice_noBroadcastSource_failToAddSource() {
+ public void startBroadcastWithConnectedDevices_noBroadcastSource_failToAddSource() {
when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
mLocalBluetoothLeBroadcast);
when(mLocalBluetoothProfileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(
@@ -203,12 +204,16 @@
when(mBluetoothMediaDevice.isBLEDevice()).thenReturn(true);
when(((BluetoothMediaDevice) mBluetoothMediaDevice).getCachedDevice()).thenReturn(
mCachedBluetoothDevice);
- when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
+ when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothFirstDevice);
List<BluetoothLeBroadcastReceiveState> sourceList = new ArrayList<>();
- when(mLocalBluetoothLeBroadcastAssistant.getAllSources(mBluetoothDevice)).thenReturn(
+ when(mLocalBluetoothLeBroadcastAssistant.getAllSources(mBluetoothFirstDevice)).thenReturn(
sourceList);
+ List<BluetoothDevice> connectedDevicesList = new ArrayList<>();
+ connectedDevicesList.add(mBluetoothFirstDevice);
+ when(mLocalBluetoothLeBroadcastAssistant.getConnectedDevices()).thenReturn(
+ connectedDevicesList);
- mMediaOutputBroadcastDialog.connectBroadcastWithActiveDevice();
+ mMediaOutputBroadcastDialog.startBroadcastWithConnectedDevices();
verify(mLocalBluetoothLeBroadcastAssistant, times(1)).addSource(any(), any(), anyBoolean());
}
@@ -360,4 +365,32 @@
assertThat(broadcastErrorMessage.getVisibility()).isEqualTo(View.VISIBLE);
}
+
+ @Test
+ public void addSourceToAllConnectedDevices() {
+ when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
+ mLocalBluetoothLeBroadcast);
+ when(mLocalBluetoothProfileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(
+ mLocalBluetoothLeBroadcastAssistant);
+ when(mLocalBluetoothLeBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(
+ mBluetoothLeBroadcastMetadata);
+ when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(mBluetoothMediaDevice);
+ when(mBluetoothMediaDevice.isBLEDevice()).thenReturn(true);
+ when(((BluetoothMediaDevice) mBluetoothMediaDevice).getCachedDevice())
+ .thenReturn(mCachedBluetoothDevice);
+ when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothFirstDevice);
+ List<BluetoothLeBroadcastReceiveState> sourceList = new ArrayList<>();
+ when(mLocalBluetoothLeBroadcastAssistant.getAllSources(mBluetoothFirstDevice)).thenReturn(
+ sourceList);
+ List<BluetoothDevice> connectedDevicesList = new ArrayList<>();
+ connectedDevicesList.add(mBluetoothFirstDevice);
+ connectedDevicesList.add(mBluetoothSecondDevice);
+ when(mLocalBluetoothLeBroadcastAssistant.getConnectedDevices()).thenReturn(
+ connectedDevicesList);
+
+ mMediaOutputBroadcastDialog.startBroadcastWithConnectedDevices();
+
+ verify(mLocalBluetoothLeBroadcastAssistant, times(2)).addSource(any(), any(), anyBoolean());
+ }
+
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt
index 826a6cc..56e3e96 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt
@@ -22,11 +22,13 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.scene.SceneTestUtils
+import com.android.systemui.scene.shared.model.ObservableTransitionState
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import com.android.systemui.scene.shared.model.SceneTransitionModel
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
@@ -91,11 +93,30 @@
val sceneTransitionProgress by collectLastValue(underTest.transitionProgress)
assertThat(sceneTransitionProgress).isEqualTo(1f)
- underTest.setSceneTransitionProgress(0.1f)
+ val transitionState =
+ MutableStateFlow<ObservableTransitionState>(
+ ObservableTransitionState.Idle(SceneKey.Lockscreen)
+ )
+ underTest.setTransitionState(transitionState)
+ assertThat(sceneTransitionProgress).isEqualTo(1f)
+
+ val progress = MutableStateFlow(1f)
+ transitionState.value =
+ ObservableTransitionState.Transition(
+ fromScene = SceneKey.Lockscreen,
+ toScene = SceneKey.Shade,
+ progress = progress,
+ )
+ assertThat(sceneTransitionProgress).isEqualTo(1f)
+
+ progress.value = 0.1f
assertThat(sceneTransitionProgress).isEqualTo(0.1f)
- underTest.setSceneTransitionProgress(0.9f)
+ progress.value = 0.9f
assertThat(sceneTransitionProgress).isEqualTo(0.9f)
+
+ underTest.setTransitionState(null)
+ assertThat(sceneTransitionProgress).isEqualTo(1f)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
index 13a602d..4facc7a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
@@ -22,11 +22,13 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.scene.SceneTestUtils
+import com.android.systemui.scene.shared.model.ObservableTransitionState
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import com.android.systemui.scene.shared.model.SceneTransitionModel
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
@@ -37,7 +39,8 @@
class SceneInteractorTest : SysuiTestCase() {
private val utils = SceneTestUtils(this)
- private val underTest = utils.sceneInteractor()
+ private val repository = utils.fakeSceneContainerRepository()
+ private val underTest = utils.sceneInteractor(repository = repository)
@Test
fun allSceneKeys() {
@@ -49,17 +52,26 @@
val currentScene by collectLastValue(underTest.currentScene)
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
- underTest.setCurrentScene(SceneModel(SceneKey.Shade))
+ underTest.setCurrentScene(SceneModel(SceneKey.Shade), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Shade))
}
@Test
fun sceneTransitionProgress() = runTest {
- val progress by collectLastValue(underTest.transitionProgress)
- assertThat(progress).isEqualTo(1f)
+ val transitionProgress by collectLastValue(underTest.transitionProgress)
+ assertThat(transitionProgress).isEqualTo(1f)
- underTest.setSceneTransitionProgress(0.55f)
- assertThat(progress).isEqualTo(0.55f)
+ val progress = MutableStateFlow(0.55f)
+ repository.setTransitionState(
+ MutableStateFlow(
+ ObservableTransitionState.Transition(
+ fromScene = SceneKey.Lockscreen,
+ toScene = SceneKey.Shade,
+ progress = progress,
+ ),
+ )
+ )
+ assertThat(transitionProgress).isEqualTo(0.55f)
}
@Test
@@ -67,10 +79,10 @@
val isVisible by collectLastValue(underTest.isVisible)
assertThat(isVisible).isTrue()
- underTest.setVisible(false)
+ underTest.setVisible(false, "reason")
assertThat(isVisible).isFalse()
- underTest.setVisible(true)
+ underTest.setVisible(true, "reason")
assertThat(isVisible).isTrue()
}
@@ -80,7 +92,7 @@
assertThat(transitions).isNull()
val initialSceneKey = underTest.currentScene.value.key
- underTest.setCurrentScene(SceneModel(SceneKey.Shade))
+ underTest.setCurrentScene(SceneModel(SceneKey.Shade), "reason")
assertThat(transitions)
.isEqualTo(
SceneTransitionModel(
@@ -89,7 +101,7 @@
)
)
- underTest.setCurrentScene(SceneModel(SceneKey.QuickSettings))
+ underTest.setCurrentScene(SceneModel(SceneKey.QuickSettings), "reason")
assertThat(transitions)
.isEqualTo(
SceneTransitionModel(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
index b6bd31f..6be19b9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
@@ -73,6 +73,7 @@
featureFlags = featureFlags,
sysUiState = sysUiState,
displayId = Display.DEFAULT_DISPLAY,
+ sceneLogger = mock(),
)
@Before
@@ -97,7 +98,7 @@
assertThat(isVisible).isFalse()
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Shade))
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Shade), "reason")
assertThat(isVisible).isTrue()
}
@@ -117,10 +118,10 @@
underTest.start()
assertThat(isVisible).isTrue()
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Gone))
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Gone), "reason")
assertThat(isVisible).isTrue()
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Shade))
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Shade), "reason")
assertThat(isVisible).isTrue()
}
@@ -326,7 +327,7 @@
SceneKey.QuickSettings,
)
.forEachIndexed { index, sceneKey ->
- sceneInteractor.setCurrentScene(SceneModel(sceneKey))
+ sceneInteractor.setCurrentScene(SceneModel(sceneKey), "reason")
runCurrent()
verify(sysUiState, times(index + 1)).commitUpdate(Display.DEFAULT_DISPLAY)
@@ -342,7 +343,7 @@
featureFlags.set(Flags.SCENE_CONTAINER, isFeatureEnabled)
authenticationRepository.setUnlocked(isDeviceUnlocked)
keyguardRepository.setBypassEnabled(isBypassEnabled)
- initialSceneKey?.let { sceneInteractor.setCurrentScene(SceneModel(it)) }
+ initialSceneKey?.let { sceneInteractor.setCurrentScene(SceneModel(it), "reason") }
}
companion object {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt
index 0ab98ad..9f3b12b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt
@@ -52,10 +52,10 @@
val isVisible by collectLastValue(underTest.isVisible)
assertThat(isVisible).isTrue()
- interactor.setVisible(false)
+ interactor.setVisible(false, "reason")
assertThat(isVisible).isFalse()
- interactor.setVisible(true)
+ interactor.setVisible(true, "reason")
assertThat(isVisible).isTrue()
}
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 9bcc8aa..c3540cf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -19,6 +19,7 @@
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static com.android.keyguard.KeyguardClockSwitch.LARGE;
+import static com.android.systemui.dump.LogBufferHelperKt.logcatLogBuffer;
import static com.google.common.truth.Truth.assertThat;
@@ -106,6 +107,7 @@
import com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel;
import com.android.systemui.keyguard.ui.viewmodel.LockscreenToOccludedTransitionViewModel;
import com.android.systemui.keyguard.ui.viewmodel.OccludedToLockscreenTransitionViewModel;
+import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel;
import com.android.systemui.media.controls.pipeline.MediaDataManager;
import com.android.systemui.media.controls.ui.KeyguardMediaController;
import com.android.systemui.media.controls.ui.MediaHierarchyManager;
@@ -220,7 +222,7 @@
@Mock protected StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
@Mock protected KeyguardStateController mKeyguardStateController;
@Mock protected DozeLog mDozeLog;
- @Mock protected ShadeLogger mShadeLog;
+ private final ShadeLogger mShadeLog = new ShadeLogger(logcatLogBuffer());
@Mock protected CommandQueue mCommandQueue;
@Mock protected VibratorHelper mVibratorHelper;
@Mock protected LatencyTracker mLatencyTracker;
@@ -300,13 +302,15 @@
@Mock protected GoneToDreamingTransitionViewModel mGoneToDreamingTransitionViewModel;
@Mock protected GoneToDreamingLockscreenHostedTransitionViewModel
mGoneToDreamingLockscreenHostedTransitionViewModel;
+ @Mock protected PrimaryBouncerToGoneTransitionViewModel
+ mPrimaryBouncerToGoneTransitionViewModel;
@Mock protected KeyguardTransitionInteractor mKeyguardTransitionInteractor;
@Mock protected KeyguardLongPressViewModel mKeyuardLongPressViewModel;
@Mock protected AlternateBouncerInteractor mAlternateBouncerInteractor;
@Mock protected MotionEvent mDownMotionEvent;
@Mock protected CoroutineDispatcher mMainDispatcher;
@Mock protected KeyguardSliceViewController mKeyguardSliceViewController;
- @Mock protected KeyguardLogger mKeyguardLogger;
+ private final KeyguardLogger mKeyguardLogger = new KeyguardLogger(logcatLogBuffer());
@Mock protected KeyguardStatusView mKeyguardStatusView;
@Captor
protected ArgumentCaptor<NotificationStackScrollLayout.OnEmptySpaceClickListener>
@@ -502,6 +506,10 @@
when(mLockscreenToOccludedTransitionViewModel.lockscreenTranslationY(anyInt()))
.thenReturn(emptyFlow());
+ // Primary Bouncer->Gone
+ when(mPrimaryBouncerToGoneTransitionViewModel.getLockscreenAlpha())
+ .thenReturn(emptyFlow());
+
NotificationWakeUpCoordinator coordinator =
new NotificationWakeUpCoordinator(
mDumpManager,
@@ -511,7 +519,7 @@
mKeyguardBypassController,
mDozeParameters,
mScreenOffAnimationController,
- mock(NotificationWakeUpCoordinatorLogger.class));
+ new NotificationWakeUpCoordinatorLogger(logcatLogBuffer()));
mConfigurationController = new ConfigurationControllerImpl(mContext);
PulseExpansionHandler expansionHandler = new PulseExpansionHandler(
mContext,
@@ -631,6 +639,7 @@
mGoneToDreamingTransitionViewModel,
mGoneToDreamingLockscreenHostedTransitionViewModel,
mLockscreenToOccludedTransitionViewModel,
+ mPrimaryBouncerToGoneTransitionViewModel,
mMainDispatcher,
mKeyguardTransitionInteractor,
mDumpManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
index fe18fb5..b6da20f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
@@ -19,6 +19,7 @@
import static android.app.Notification.FLAG_FSI_REQUESTED_BUT_DENIED;
+import static com.android.systemui.dump.LogBufferHelperKt.logcatLogBuffer;
import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED;
import static junit.framework.Assert.assertFalse;
@@ -45,7 +46,6 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.HeadsUpManagerLogger;
import org.junit.After;
@@ -73,9 +73,7 @@
// Number of notifications to use in tests requiring multiple notifications
private static final int TEST_NUM_NOTIFICATIONS = 4;
protected static final int TEST_TIMEOUT_TIME = 15000;
- protected final Runnable TEST_TIMEOUT_RUNNABLE = () -> mTimedOut = true;
-
- private AlertingNotificationManager mAlertingNotificationManager;
+ protected final Runnable mTestTimeoutRunnable = () -> mTimedOut = true;
protected NotificationEntry mEntry;
protected Handler mTestHandler;
@@ -84,11 +82,11 @@
@Mock protected ExpandableNotificationRow mRow;
- private final class TestableAlertingNotificationManager extends AlertingNotificationManager {
+ private static class TestableAlertingNotificationManager extends AlertingNotificationManager {
private AlertEntry mLastCreatedEntry;
private TestableAlertingNotificationManager(Handler handler) {
- super(mock(HeadsUpManagerLogger.class), handler);
+ super(new HeadsUpManagerLogger(logcatLogBuffer()), handler);
mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME;
mStickyDisplayTime = TEST_STICKY_DISPLAY_TIME;
mAutoDismissNotificationDecay = TEST_AUTO_DISMISS_TIME;
@@ -112,8 +110,8 @@
}
}
- protected AlertingNotificationManager createAlertingNotificationManager(Handler handler) {
- return new TestableAlertingNotificationManager(handler);
+ protected AlertingNotificationManager createAlertingNotificationManager() {
+ return new TestableAlertingNotificationManager(mTestHandler);
}
protected StatusBarNotification createNewSbn(int id, Notification n) {
@@ -169,8 +167,6 @@
.setSbn(mSbn)
.build();
mEntry.setRow(mRow);
-
- mAlertingNotificationManager = createAlertingNotificationManager(mTestHandler);
}
@After
@@ -180,68 +176,74 @@
@Test
public void testShowNotification_addsEntry() {
- mAlertingNotificationManager.showNotification(mEntry);
+ AlertingNotificationManager alm = createAlertingNotificationManager();
- assertTrue(mAlertingNotificationManager.isAlerting(mEntry.getKey()));
- assertTrue(mAlertingNotificationManager.hasNotifications());
- assertEquals(mEntry, mAlertingNotificationManager.getEntry(mEntry.getKey()));
+ alm.showNotification(mEntry);
+
+ assertTrue(alm.isAlerting(mEntry.getKey()));
+ assertTrue(alm.hasNotifications());
+ assertEquals(mEntry, alm.getEntry(mEntry.getKey()));
}
@Test
public void testShowNotification_autoDismisses() {
- mAlertingNotificationManager.showNotification(mEntry);
- mTestHandler.postDelayed(TEST_TIMEOUT_RUNNABLE, TEST_TIMEOUT_TIME);
+ AlertingNotificationManager alm = createAlertingNotificationManager();
+
+ alm.showNotification(mEntry);
+ mTestHandler.postDelayed(mTestTimeoutRunnable, TEST_TIMEOUT_TIME);
// Wait for remove runnable and then process it immediately
TestableLooper.get(this).processMessages(1);
assertFalse("Test timed out", mTimedOut);
- assertFalse(mAlertingNotificationManager.isAlerting(mEntry.getKey()));
+ assertFalse(alm.isAlerting(mEntry.getKey()));
}
@Test
public void testRemoveNotification_removeDeferred() {
- mAlertingNotificationManager.showNotification(mEntry);
+ AlertingNotificationManager alm = createAlertingNotificationManager();
+ alm.showNotification(mEntry);
// Try to remove but defer, since the notification has not been shown long enough.
- mAlertingNotificationManager.removeNotification(
- mEntry.getKey(), false /* releaseImmediately */);
+ alm.removeNotification(mEntry.getKey(), false /* releaseImmediately */);
- assertTrue(mAlertingNotificationManager.isAlerting(mEntry.getKey()));
+ assertTrue(alm.isAlerting(mEntry.getKey()));
}
@Test
public void testRemoveNotification_forceRemove() {
- mAlertingNotificationManager.showNotification(mEntry);
+ AlertingNotificationManager alm = createAlertingNotificationManager();
+ alm.showNotification(mEntry);
// Remove forcibly with releaseImmediately = true.
- mAlertingNotificationManager.removeNotification(
- mEntry.getKey(), true /* releaseImmediately */);
+ alm.removeNotification(mEntry.getKey(), true /* releaseImmediately */);
- assertFalse(mAlertingNotificationManager.isAlerting(mEntry.getKey()));
+ assertFalse(alm.isAlerting(mEntry.getKey()));
}
@Test
public void testReleaseAllImmediately() {
+ AlertingNotificationManager alm = createAlertingNotificationManager();
for (int i = 0; i < TEST_NUM_NOTIFICATIONS; i++) {
StatusBarNotification sbn = createNewNotification(i);
NotificationEntry entry = new NotificationEntryBuilder()
.setSbn(sbn)
.build();
entry.setRow(mRow);
- mAlertingNotificationManager.showNotification(entry);
+ alm.showNotification(entry);
}
- mAlertingNotificationManager.releaseAllImmediately();
+ alm.releaseAllImmediately();
- assertEquals(0, mAlertingNotificationManager.getAllEntries().count());
+ assertEquals(0, alm.getAllEntries().count());
}
@Test
public void testCanRemoveImmediately_notShownLongEnough() {
- mAlertingNotificationManager.showNotification(mEntry);
+ AlertingNotificationManager alm = createAlertingNotificationManager();
+ alm.showNotification(mEntry);
// The entry has just been added so we should not remove immediately.
- assertFalse(mAlertingNotificationManager.canRemoveImmediately(mEntry.getKey()));
+ assertFalse(alm.canRemoveImmediately(mEntry.getKey()));
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
index 305f48b..764f7b6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar;
+import static com.android.systemui.dump.LogBufferHelperKt.logcatLogBuffer;
+
import static junit.framework.Assert.assertTrue;
import static org.mockito.Mockito.mock;
@@ -82,9 +84,9 @@
mPowerInteractor,
mStateController,
mRemoteInputUriController,
- mock(RemoteInputControllerLogger.class),
+ new RemoteInputControllerLogger(logcatLogBuffer()),
mClickNotifier,
- mock(ActionClickLogger.class),
+ new ActionClickLogger(logcatLogBuffer()),
mock(DumpManager.class));
mEntry = new NotificationEntryBuilder()
.setPkg(TEST_PACKAGE_NAME)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt
index da3a9f6..78c0982 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt
@@ -22,6 +22,7 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
+import com.android.systemui.dump.logcatLogBuffer
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.shade.ShadeViewController.Companion.WAKEUP_ANIMATION_DELAY_MS
import com.android.systemui.statusbar.StatusBarState
@@ -59,7 +60,7 @@
private val bypassController: KeyguardBypassController = mock()
private val dozeParameters: DozeParameters = mock()
private val screenOffAnimationController: ScreenOffAnimationController = mock()
- private val logger: NotificationWakeUpCoordinatorLogger = mock()
+ private val logger = NotificationWakeUpCoordinatorLogger(logcatLogBuffer())
private val stackScrollerController: NotificationStackScrollLayoutController = mock()
private val wakeUpListener: NotificationWakeUpCoordinator.WakeUpListener = mock()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
index 9037df8..104b751 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
@@ -26,6 +26,7 @@
import static android.service.notification.NotificationStats.DISMISSAL_SHADE;
import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
+import static com.android.systemui.dump.LogBufferHelperKt.logcatLogBuffer;
import static com.android.systemui.statusbar.notification.collection.NotifCollection.REASON_NOT_CANCELED;
import static com.android.systemui.statusbar.notification.collection.NotifCollection.REASON_UNKNOWN;
import static com.android.systemui.statusbar.notification.collection.NotificationEntry.DismissState.DISMISSED;
@@ -47,6 +48,7 @@
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -120,7 +122,7 @@
@Mock private IStatusBarService mStatusBarService;
@Mock private NotifPipelineFlags mNotifPipelineFlags;
- @Mock private NotifCollectionLogger mLogger;
+ private final NotifCollectionLogger mLogger = spy(new NotifCollectionLogger(logcatLogBuffer()));
@Mock private LogBufferEulogizer mEulogizer;
@Mock private Handler mMainHandler;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
index a869038..bfa03ee 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.collection;
+import static com.android.systemui.dump.LogBufferHelperKt.logcatLogBuffer;
import static com.android.systemui.statusbar.notification.collection.ListDumper.dumpTree;
import static com.android.systemui.statusbar.notification.collection.ShadeListBuilder.MAX_CONSECUTIVE_REENTRANT_REBUILDS;
@@ -101,10 +102,10 @@
public class ShadeListBuilderTest extends SysuiTestCase {
private ShadeListBuilder mListBuilder;
- private FakeSystemClock mSystemClock = new FakeSystemClock();
-
- @Mock private NotifPipelineFlags mNotifPipelineFlags;
- @Mock private ShadeListBuilderLogger mLogger;
+ private final FakeSystemClock mSystemClock = new FakeSystemClock();
+ private final NotifPipelineFlags mNotifPipelineFlags = mock(NotifPipelineFlags.class);
+ private final ShadeListBuilderLogger mLogger = new ShadeListBuilderLogger(
+ mNotifPipelineFlags, logcatLogBuffer());
@Mock private DumpManager mDumpManager;
@Mock private NotifCollection mNotifCollection;
@Mock private NotificationInteractionTracker mInteractionTracker;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerTest.java
index ac9a570..3dcfcfa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerTest.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.notification.collection.coalescer;
+import static com.android.systemui.dump.LogBufferHelperKt.logcatLogBuffer;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.Mockito.clearInvocations;
@@ -62,8 +64,7 @@
@Mock private NotificationListener mListenerService;
@Mock private GroupCoalescer.BatchableNotificationHandler mListener;
- @Mock private GroupCoalescerLogger mLogger;
-
+ private final GroupCoalescerLogger mLogger = new GroupCoalescerLogger(logcatLogBuffer());
@Captor private ArgumentCaptor<NotificationHandler> mListenerCaptor;
private final NoManSimulator mNoMan = new NoManSimulator();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt
index 4143647..362da0b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt
@@ -20,6 +20,7 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
+import com.android.systemui.dump.logcatLogBuffer
import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
@@ -28,6 +29,7 @@
import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewListener
import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewManager
import com.android.systemui.statusbar.notification.row.NotificationGuts
+import com.android.systemui.statusbar.notification.row.NotificationGuts.GutsContent
import com.android.systemui.util.mockito.withArgCaptor
import com.google.common.truth.Truth.assertThat
import org.junit.Before
@@ -36,6 +38,7 @@
import org.mockito.Mock
import org.mockito.Mockito.mock
import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations.initMocks
@SmallTest
@@ -52,8 +55,9 @@
@Mock private lateinit var notifGutsViewManager: NotifGutsViewManager
@Mock private lateinit var pipeline: NotifPipeline
@Mock private lateinit var dumpManager: DumpManager
- @Mock private lateinit var logger: GutsCoordinatorLogger
+ private val logger = GutsCoordinatorLogger(logcatLogBuffer())
@Mock private lateinit var lifetimeExtenderCallback: OnEndLifetimeExtensionCallback
+ @Mock private lateinit var notificationGuts: NotificationGuts
@Before
fun setUp() {
@@ -69,12 +73,13 @@
notifLifetimeExtender.setCallback(lifetimeExtenderCallback)
entry1 = NotificationEntryBuilder().setId(1).build()
entry2 = NotificationEntryBuilder().setId(2).build()
+ whenever(notificationGuts.gutsContent).thenReturn(mock(GutsContent::class.java))
}
@Test
fun testSimpleLifetimeExtension() {
assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isFalse()
- notifGutsViewListener.onGutsOpen(entry1, mock(NotificationGuts::class.java))
+ notifGutsViewListener.onGutsOpen(entry1, notificationGuts)
assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isTrue()
notifGutsViewListener.onGutsClose(entry1)
verify(lifetimeExtenderCallback).onEndLifetimeExtension(notifLifetimeExtender, entry1)
@@ -84,9 +89,9 @@
@Test
fun testDoubleOpenLifetimeExtension() {
assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isFalse()
- notifGutsViewListener.onGutsOpen(entry1, mock(NotificationGuts::class.java))
+ notifGutsViewListener.onGutsOpen(entry1, notificationGuts)
assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isTrue()
- notifGutsViewListener.onGutsOpen(entry1, mock(NotificationGuts::class.java))
+ notifGutsViewListener.onGutsOpen(entry1, notificationGuts)
assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isTrue()
notifGutsViewListener.onGutsClose(entry1)
verify(lifetimeExtenderCallback).onEndLifetimeExtension(notifLifetimeExtender, entry1)
@@ -97,10 +102,10 @@
fun testTwoEntryLifetimeExtension() {
assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isFalse()
assertThat(notifLifetimeExtender.maybeExtendLifetime(entry2, 0)).isFalse()
- notifGutsViewListener.onGutsOpen(entry1, mock(NotificationGuts::class.java))
+ notifGutsViewListener.onGutsOpen(entry1, notificationGuts)
assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isTrue()
assertThat(notifLifetimeExtender.maybeExtendLifetime(entry2, 0)).isFalse()
- notifGutsViewListener.onGutsOpen(entry2, mock(NotificationGuts::class.java))
+ notifGutsViewListener.onGutsOpen(entry2, notificationGuts)
assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isTrue()
assertThat(notifLifetimeExtender.maybeExtendLifetime(entry2, 0)).isTrue()
notifGutsViewListener.onGutsClose(entry1)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
index ea70e9e..fbd61f4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
@@ -25,6 +25,7 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.advanceTimeBy
import com.android.systemui.dump.DumpManager
+import com.android.systemui.dump.logcatLogBuffer
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
@@ -606,7 +607,7 @@
keyguardNotifVisibilityProvider,
keyguardRepository,
keyguardTransitionRepository,
- mock<KeyguardCoordinatorLogger>(),
+ KeyguardCoordinatorLogger(logcatLogBuffer()),
testScope.backgroundScope,
sectionHeaderVisibilityProvider,
fakeSettings,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java
index b5e77e0..548ecde 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java
@@ -18,6 +18,7 @@
import static android.provider.Settings.Secure.SHOW_NOTIFICATION_SNOOZE;
+import static com.android.systemui.dump.LogBufferHelperKt.logcatLogBuffer;
import static com.android.systemui.statusbar.notification.collection.GroupEntry.ROOT_ENTRY;
import static org.junit.Assert.assertFalse;
@@ -134,7 +135,7 @@
setSectionIsLowPriority(false);
PreparationCoordinator coordinator = new PreparationCoordinator(
- mock(PreparationCoordinatorLogger.class),
+ new PreparationCoordinatorLogger(logcatLogBuffer()),
mNotifInflater,
mErrorManager,
mock(NotifViewBarn.class),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorTest.kt
index 5793364..069eec2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorTest.kt
@@ -21,6 +21,7 @@
import android.testing.TestableLooper.RunWithLooper
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.logcatLogBuffer
import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
@@ -50,7 +51,7 @@
private lateinit var entry2: NotificationEntry
@Mock private lateinit var pipeline: NotifPipeline
- @Mock private lateinit var logger: ShadeEventCoordinatorLogger
+ private val logger = ShadeEventCoordinatorLogger(logcatLogBuffer())
@Mock private lateinit var executor: Executor
@Mock private lateinit var notifRemovedByUserCallback: Runnable
@Mock private lateinit var shadeEmptiedCallback: Runnable
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionInconsistencyTrackerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionInconsistencyTrackerTest.kt
index 6eb391a..0b61a8d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionInconsistencyTrackerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionInconsistencyTrackerTest.kt
@@ -21,14 +21,15 @@
import android.testing.TestableLooper.RunWithLooper
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.logcatLogBuffer
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
import com.android.systemui.util.mockito.eq
-import com.android.systemui.util.mockito.mock
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.clearInvocations
+import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
@@ -36,7 +37,7 @@
@RunWith(AndroidTestingRunner::class)
@RunWithLooper
class NotifCollectionInconsistencyTrackerTest : SysuiTestCase() {
- private val logger: NotifCollectionLogger = mock()
+ private val logger = spy(NotifCollectionLogger(logcatLogBuffer()))
private val entry1: NotificationEntry = NotificationEntryBuilder().setId(1).build()
private val entry2: NotificationEntry = NotificationEntryBuilder().setId(2).build()
private val collectionSet = mutableSetOf<String>()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderTest.kt
index ac254ab..bad56a3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderTest.kt
@@ -18,6 +18,7 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.logcatLogBuffer
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager
import com.android.systemui.statusbar.notification.collection.GroupEntry
import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder
@@ -46,7 +47,7 @@
private val sectionsFeatureManager: NotificationSectionsFeatureManager = mock()
private val sectionHeaderVisibilityProvider: SectionHeaderVisibilityProvider = mock()
private val viewBarn: NotifViewBarn = mock()
- private val logger: NodeSpecBuilderLogger = mock()
+ private val logger = NodeSpecBuilderLogger(mock(), logcatLogBuffer())
private var rootController: NodeController = buildFakeController("rootController")
private var headerController0: NodeController = buildFakeController("header0")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferTest.kt
index 6167b46..9a60272 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferTest.kt
@@ -22,7 +22,7 @@
import android.widget.FrameLayout
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.util.mockito.mock
+import com.android.systemui.dump.logcatLogBuffer
import org.junit.Assert
import org.junit.Before
import org.junit.Test
@@ -30,6 +30,7 @@
import org.mockito.ArgumentMatchers.isNull
import org.mockito.Mockito.anyBoolean
import org.mockito.Mockito.matches
+import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
@SmallTest
@@ -44,7 +45,7 @@
private val controller5 = FakeController(mContext, "Controller5")
private val controller6 = FakeController(mContext, "Controller6")
private val controller7 = FakeController(mContext, "Controller7")
- private val logger: ShadeViewDifferLogger = mock()
+ private val logger = spy(ShadeViewDifferLogger(logcatLogBuffer()))
@Before
fun setUp() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderTest.java
index ca65987..04ffab3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderTest.java
@@ -16,9 +16,12 @@
package com.android.systemui.statusbar.notification.interruption;
+import static com.android.systemui.dump.LogBufferHelperKt.logcatLogBuffer;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
@@ -50,7 +53,8 @@
private HeadsUpViewBinder mViewBinder;
@Mock private NotificationMessagingUtil mNotificationMessagingUtil;
@Mock private RowContentBindStage mBindStage;
- @Mock private HeadsUpViewBinderLogger mLogger;
+ private final HeadsUpViewBinderLogger mLogger = spy(
+ new HeadsUpViewBinderLogger(logcatLogBuffer()));
@Mock private NotificationEntry mEntry;
@Mock private ExpandableNotificationRow mRow;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
index 4d4d319..764005b8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
@@ -17,10 +17,6 @@
package com.android.systemui.statusbar.notification.row
-import android.app.Notification
-import android.net.Uri
-import android.os.UserHandle
-import android.os.UserHandle.USER_ALL
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import androidx.test.filters.SmallTest
@@ -28,21 +24,18 @@
import com.android.internal.statusbar.IStatusBarService
import com.android.systemui.SysuiTestCase
import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.dump.logcatLogBuffer
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.plugins.PluginManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.statusbar.SbnBuilder
import com.android.systemui.statusbar.SmartReplyController
-import com.android.systemui.statusbar.notification.collection.NotificationEntry
-import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
import com.android.systemui.statusbar.notification.collection.provider.NotificationDismissibilityProvider
import com.android.systemui.statusbar.notification.collection.render.FakeNodeController
import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager
import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager
import com.android.systemui.statusbar.notification.logging.NotificationLogger
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController.BUBBLES_SETTING_URI
import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer
import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainerLogger
import com.android.systemui.statusbar.notification.stack.NotificationListContainer
@@ -53,9 +46,9 @@
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.mock
-import com.android.systemui.util.mockito.withArgCaptor
import com.android.systemui.util.time.SystemClock
import com.android.systemui.wmshell.BubblesManager
+import java.util.Optional
import junit.framework.Assert
import org.junit.After
import org.junit.Before
@@ -63,10 +56,8 @@
import org.junit.runner.RunWith
import org.mockito.Mockito
import org.mockito.Mockito.anyBoolean
-import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
-import java.util.*
import org.mockito.Mockito.`when` as whenever
@SmallTest
@@ -81,7 +72,7 @@
private val activableNotificationViewController: ActivatableNotificationViewController = mock()
private val rivSubComponentFactory: RemoteInputViewSubcomponent.Factory = mock()
private val metricsLogger: MetricsLogger = mock()
- private val logBufferLogger: NotificationRowLogger = mock()
+ private val logBufferLogger = NotificationRowLogger(logcatLogBuffer(), logcatLogBuffer())
private val listContainer: NotificationListContainer = mock()
private val childrenContainer: NotificationChildrenContainer = mock()
private val smartReplyConstants: SmartReplyConstants = mock()
@@ -103,10 +94,10 @@
private val featureFlags: FeatureFlags = mock()
private val peopleNotificationIdentifier: PeopleNotificationIdentifier = mock()
private val bubblesManager: BubblesManager = mock()
- private val settingsController: NotificationSettingsController = mock()
private val dragController: ExpandableNotificationRowDragController = mock()
private val dismissibilityProvider: NotificationDismissibilityProvider = mock()
private val statusBarService: IStatusBarService = mock()
+
private lateinit var controller: ExpandableNotificationRowController
@Before
@@ -119,7 +110,7 @@
rivSubComponentFactory,
metricsLogger,
logBufferLogger,
- mock<NotificationChildrenContainerLogger>(),
+ NotificationChildrenContainerLogger(logcatLogBuffer()),
listContainer,
smartReplyConstants,
smartReplyController,
@@ -143,16 +134,11 @@
featureFlags,
peopleNotificationIdentifier,
Optional.of(bubblesManager),
- settingsController,
dragController,
dismissibilityProvider,
statusBarService
)
whenever(view.childrenContainer).thenReturn(childrenContainer)
-
- val notification = Notification.Builder(mContext).build()
- val sbn = SbnBuilder().setNotification(notification).build()
- whenever(view.entry).thenReturn(NotificationEntryBuilder().setSbn(sbn).build())
}
@After
@@ -165,13 +151,13 @@
whenever(view.isParentDismissed).thenReturn(true)
Assert.assertTrue(controller.offerToKeepInParentForAnimation())
- Mockito.verify(view).setKeepInParentForDismissAnimation(true)
+ verify(view).setKeepInParentForDismissAnimation(true)
}
@Test
fun offerKeepInParent_parentNotDismissed() {
Assert.assertFalse(controller.offerToKeepInParentForAnimation())
- Mockito.verify(view, never()).setKeepInParentForDismissAnimation(anyBoolean())
+ verify(view, never()).setKeepInParentForDismissAnimation(anyBoolean())
}
@Test
@@ -181,7 +167,7 @@
whenever(view.keepInParentForDismissAnimation()).thenReturn(true)
Assert.assertTrue(controller.removeFromParentIfKeptForAnimation())
- Mockito.verify(parentView).removeChildNotification(view)
+ verify(parentView).removeChildNotification(view)
}
@Test
@@ -202,9 +188,9 @@
controller.removeChild(childNodeController, /* isTransfer= */ true)
// VERIFY the listContainer is not notified
- Mockito.verify(childView).isChangingPosition = eq(true)
- Mockito.verify(view).removeChildNotification(eq(childView))
- Mockito.verify(listContainer, never()).notifyGroupChildRemoved(any(), any())
+ verify(childView).isChangingPosition = eq(true)
+ verify(view).removeChildNotification(eq(childView))
+ verify(listContainer, never()).notifyGroupChildRemoved(any(), any())
}
@Test
@@ -216,78 +202,8 @@
controller.removeChild(childNodeController, /* isTransfer= */ false)
// VERIFY the listContainer is passed the childrenContainer for transient animations
- Mockito.verify(childView, never()).isChangingPosition = any()
- Mockito.verify(view).removeChildNotification(eq(childView))
- Mockito.verify(listContainer).notifyGroupChildRemoved(eq(childView), eq(childrenContainer))
- }
-
- @Test
- fun registerSettingsListener_forBubbles() {
- controller.init(mock(NotificationEntry::class.java))
- val viewStateObserver = withArgCaptor {
- verify(view).addOnAttachStateChangeListener(capture());
- }
- viewStateObserver.onViewAttachedToWindow(view);
- verify(settingsController).addCallback(any(), any());
- }
-
- @Test
- fun unregisterSettingsListener_forBubbles() {
- controller.init(mock(NotificationEntry::class.java))
- val viewStateObserver = withArgCaptor {
- verify(view).addOnAttachStateChangeListener(capture());
- }
- viewStateObserver.onViewDetachedFromWindow(view);
- verify(settingsController).removeCallback(any(), any());
- }
-
- @Test
- fun settingsListener_invalidUri() {
- controller.mSettingsListener.onSettingChanged(Uri.EMPTY, view.entry.sbn.userId, "1")
-
- verify(view, never()).getPrivateLayout()
- }
-
- @Test
- fun settingsListener_invalidUserId() {
- controller.mSettingsListener.onSettingChanged(BUBBLES_SETTING_URI, -1000, "1")
- controller.mSettingsListener.onSettingChanged(BUBBLES_SETTING_URI, -1000, null)
-
- verify(view, never()).getPrivateLayout()
- }
-
- @Test
- fun settingsListener_validUserId() {
- val childView: NotificationContentView = mock()
- whenever(view.privateLayout).thenReturn(childView)
-
- controller.mSettingsListener.onSettingChanged(
- BUBBLES_SETTING_URI, view.entry.sbn.userId, "1")
- verify(childView).setBubblesEnabledForUser(true)
-
- controller.mSettingsListener.onSettingChanged(
- BUBBLES_SETTING_URI, view.entry.sbn.userId, "9")
- verify(childView).setBubblesEnabledForUser(false)
- }
-
- @Test
- fun settingsListener_userAll() {
- val childView: NotificationContentView = mock()
- whenever(view.privateLayout).thenReturn(childView)
-
- val notification = Notification.Builder(mContext).build()
- val sbn = SbnBuilder().setNotification(notification)
- .setUser(UserHandle.of(USER_ALL))
- .build()
- whenever(view.entry).thenReturn(NotificationEntryBuilder()
- .setSbn(sbn)
- .setUser(UserHandle.of(USER_ALL))
- .build())
-
- controller.mSettingsListener.onSettingChanged(BUBBLES_SETTING_URI, 9, "1")
- verify(childView).setBubblesEnabledForUser(true)
-
- controller.mSettingsListener.onSettingChanged(BUBBLES_SETTING_URI, 1, "0")
- verify(childView).setBubblesEnabledForUser(false)
+ verify(childView, never()).isChangingPosition = any()
+ verify(view).removeChildNotification(eq(childView))
+ verify(listContainer).notifyGroupChildRemoved(eq(childView), eq(childrenContainer))
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineTest.java
index bdd82fd..cf5b3cd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineTest.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.notification.row;
+import static com.android.systemui.dump.LogBufferHelperKt.logcatLogBuffer;
+
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -61,7 +63,7 @@
mBindPipeline = new NotifBindPipeline(
collection,
- mock(NotifBindPipelineLogger.class),
+ new NotifBindPipelineLogger(logcatLogBuffer()),
TestableLooper.get(this).getLooper());
mBindPipeline.setStage(mStage);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt
index ba6c7fd..0b90ebe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt
@@ -250,9 +250,6 @@
.thenReturn(actionListMarginTarget)
view.setContainingNotification(mockContainingNotification)
- // Given: controller says bubbles are enabled for the user
- view.setBubblesEnabledForUser(true);
-
// When: call NotificationContentView.setExpandedChild() to set the expandedChild
view.expandedChild = mockExpandedChild
@@ -304,9 +301,6 @@
view.expandedChild = mockExpandedChild
assertEquals(notificationContentMargin, getMarginBottom(actionListMarginTarget))
- // Given: controller says bubbles are enabled for the user
- view.setBubblesEnabledForUser(true);
-
// When: call NotificationContentView.onNotificationUpdated() to update the
// NotificationEntry, which should show bubble button
view.onNotificationUpdated(createMockNotificationEntry(true))
@@ -411,6 +405,7 @@
val userMock: UserHandle = mock()
whenever(this.sbn).thenReturn(sbnMock)
whenever(sbnMock.user).thenReturn(userMock)
+ doReturn(showButton).whenever(view).shouldShowBubbleButton(this)
}
private fun createLinearLayoutWithBottomMargin(bottomMargin: Int): LinearLayout {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationSettingsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationSettingsControllerTest.kt
deleted file mode 100644
index 2bccdca..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationSettingsControllerTest.kt
+++ /dev/null
@@ -1,245 +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.statusbar.notification.row
-
-import android.app.ActivityManager
-import android.database.ContentObserver
-import android.net.Uri
-import android.os.Handler
-import android.provider.Settings.Secure
-import android.testing.AndroidTestingRunner
-import android.testing.TestableLooper
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.dump.DumpManager
-import com.android.systemui.settings.UserTracker
-import com.android.systemui.statusbar.notification.row.NotificationSettingsController.Listener
-import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.capture
-import com.android.systemui.util.mockito.eq
-import com.android.systemui.util.mockito.mock
-import com.android.systemui.util.mockito.whenever
-import com.android.systemui.util.settings.SecureSettings
-import org.junit.After
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.ArgumentCaptor
-import org.mockito.ArgumentMatchers
-import org.mockito.ArgumentMatchers.anyInt
-import org.mockito.ArgumentMatchers.anyString
-import org.mockito.Captor
-import org.mockito.Mock
-import org.mockito.Mockito
-import org.mockito.Mockito.anyBoolean
-import org.mockito.Mockito.never
-import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
-
-@SmallTest
-@RunWith(AndroidTestingRunner::class)
-@TestableLooper.RunWithLooper
-class NotificationSettingsControllerTest : SysuiTestCase() {
-
- val setting1: String = Secure.NOTIFICATION_BUBBLES
- val setting2: String = Secure.ACCESSIBILITY_ENABLED
- val settingUri1: Uri = Secure.getUriFor(setting1)
- val settingUri2: Uri = Secure.getUriFor(setting2)
-
- @Mock
- private lateinit var userTracker: UserTracker
- private lateinit var handler: Handler
- private lateinit var testableLooper: TestableLooper
- @Mock
- private lateinit var secureSettings: SecureSettings
- @Mock
- private lateinit var dumpManager: DumpManager
-
- @Captor
- private lateinit var userTrackerCallbackCaptor: ArgumentCaptor<UserTracker.Callback>
- @Captor
- private lateinit var settingsObserverCaptor: ArgumentCaptor<ContentObserver>
-
- private lateinit var controller: NotificationSettingsController
-
- @Before
- fun setUp() {
- MockitoAnnotations.initMocks(this)
- testableLooper = TestableLooper.get(this)
- handler = Handler(testableLooper.looper)
- allowTestableLooperAsMainThread()
- controller =
- NotificationSettingsController(
- userTracker,
- handler,
- secureSettings,
- dumpManager
- )
- }
-
- @After
- fun tearDown() {
- disallowTestableLooperAsMainThread()
- }
-
- @Test
- fun creationRegistersCallbacks() {
- verify(userTracker).addCallback(any(), any())
- verify(dumpManager).registerNormalDumpable(anyString(), eq(controller))
- }
- @Test
- fun updateContentObserverRegistration_onUserChange_noSettingsListeners() {
- verify(userTracker).addCallback(capture(userTrackerCallbackCaptor), any())
- val userCallback = userTrackerCallbackCaptor.value
- val userId = 9
-
- // When: User is changed
- userCallback.onUserChanged(userId, context)
-
- // Validate: Nothing to do, since we aren't monitoring settings
- verify(secureSettings, never()).unregisterContentObserver(any())
- verify(secureSettings, never()).registerContentObserverForUser(
- any(Uri::class.java), anyBoolean(), any(), anyInt())
- }
- @Test
- fun updateContentObserverRegistration_onUserChange_withSettingsListeners() {
- // When: someone is listening to a setting
- controller.addCallback(settingUri1,
- Mockito.mock(Listener::class.java))
-
- verify(userTracker).addCallback(capture(userTrackerCallbackCaptor), any())
- val userCallback = userTrackerCallbackCaptor.value
- val userId = 9
-
- // Then: User is changed
- userCallback.onUserChanged(userId, context)
-
- // Validate: The tracker is unregistered and re-registered with the new user
- verify(secureSettings).unregisterContentObserver(any())
- verify(secureSettings).registerContentObserverForUser(
- eq(settingUri1), eq(false), any(), eq(userId))
- }
-
- @Test
- fun addCallback_onlyFirstForUriRegistersObserver() {
- controller.addCallback(settingUri1,
- Mockito.mock(Listener::class.java))
- verify(secureSettings).registerContentObserverForUser(
- eq(settingUri1), eq(false), any(), eq(ActivityManager.getCurrentUser()))
-
- controller.addCallback(settingUri1,
- Mockito.mock(Listener::class.java))
- verify(secureSettings).registerContentObserverForUser(
- any(Uri::class.java), anyBoolean(), any(), anyInt())
- }
-
- @Test
- fun addCallback_secondUriRegistersObserver() {
- controller.addCallback(settingUri1,
- Mockito.mock(Listener::class.java))
- verify(secureSettings).registerContentObserverForUser(
- eq(settingUri1), eq(false), any(), eq(ActivityManager.getCurrentUser()))
-
- controller.addCallback(settingUri2,
- Mockito.mock(Listener::class.java))
- verify(secureSettings).registerContentObserverForUser(
- eq(settingUri2), eq(false), any(), eq(ActivityManager.getCurrentUser()))
- verify(secureSettings).registerContentObserverForUser(
- eq(settingUri1), anyBoolean(), any(), anyInt())
- }
-
- @Test
- fun removeCallback_lastUnregistersObserver() {
- val listenerSetting1 : Listener = mock()
- val listenerSetting2 : Listener = mock()
- controller.addCallback(settingUri1, listenerSetting1)
- verify(secureSettings).registerContentObserverForUser(
- eq(settingUri1), eq(false), any(), eq(ActivityManager.getCurrentUser()))
-
- controller.addCallback(settingUri2, listenerSetting2)
- verify(secureSettings).registerContentObserverForUser(
- eq(settingUri2), anyBoolean(), any(), anyInt())
-
- controller.removeCallback(settingUri2, listenerSetting2)
- verify(secureSettings, never()).unregisterContentObserver(any())
-
- controller.removeCallback(settingUri1, listenerSetting1)
- verify(secureSettings).unregisterContentObserver(any())
- }
-
- @Test
- fun addCallback_updatesCurrentValue() {
- whenever(secureSettings.getStringForUser(
- setting1, ActivityManager.getCurrentUser())).thenReturn("9")
- whenever(secureSettings.getStringForUser(
- setting2, ActivityManager.getCurrentUser())).thenReturn("5")
-
- val listenerSetting1a : Listener = mock()
- val listenerSetting1b : Listener = mock()
- val listenerSetting2 : Listener = mock()
-
- controller.addCallback(settingUri1, listenerSetting1a)
- controller.addCallback(settingUri1, listenerSetting1b)
- controller.addCallback(settingUri2, listenerSetting2)
-
- testableLooper.processAllMessages()
-
- verify(listenerSetting1a).onSettingChanged(
- settingUri1, ActivityManager.getCurrentUser(), "9")
- verify(listenerSetting1b).onSettingChanged(
- settingUri1, ActivityManager.getCurrentUser(), "9")
- verify(listenerSetting2).onSettingChanged(
- settingUri2, ActivityManager.getCurrentUser(), "5")
- }
-
- @Test
- fun removeCallback_noMoreUpdates() {
- whenever(secureSettings.getStringForUser(
- setting1, ActivityManager.getCurrentUser())).thenReturn("9")
-
- val listenerSetting1a : Listener = mock()
- val listenerSetting1b : Listener = mock()
-
- // First, register
- controller.addCallback(settingUri1, listenerSetting1a)
- controller.addCallback(settingUri1, listenerSetting1b)
- testableLooper.processAllMessages()
-
- verify(secureSettings).registerContentObserverForUser(
- any(Uri::class.java), anyBoolean(), capture(settingsObserverCaptor), anyInt())
- verify(listenerSetting1a).onSettingChanged(
- settingUri1, ActivityManager.getCurrentUser(), "9")
- verify(listenerSetting1b).onSettingChanged(
- settingUri1, ActivityManager.getCurrentUser(), "9")
- Mockito.clearInvocations(listenerSetting1b)
- Mockito.clearInvocations(listenerSetting1a)
-
- // Remove one of them
- controller.removeCallback(settingUri1, listenerSetting1a)
-
- // On update, only remaining listener should get the callback
- settingsObserverCaptor.value.onChange(false, settingUri1)
- testableLooper.processAllMessages()
-
- verify(listenerSetting1a, never()).onSettingChanged(
- settingUri1, ActivityManager.getCurrentUser(), "9")
- verify(listenerSetting1b).onSettingChanged(
- settingUri1, ActivityManager.getCurrentUser(), "9")
- }
-
-}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index d21029d..1ab2b38 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -21,6 +21,7 @@
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
import static android.app.NotificationManager.IMPORTANCE_HIGH;
+import static com.android.systemui.dump.LogBufferHelperKt.logcatLogBuffer;
import static com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking;
import static org.junit.Assert.assertEquals;
@@ -178,13 +179,13 @@
contentBinder.setInflateSynchronously(true);
mBindStage = new RowContentBindStage(contentBinder,
mock(NotifInflationErrorManager.class),
- mock(RowContentBindStageLogger.class));
+ new RowContentBindStageLogger(logcatLogBuffer()));
CommonNotifCollection collection = mock(CommonNotifCollection.class);
mBindPipeline = new NotifBindPipeline(
collection,
- mock(NotifBindPipelineLogger.class),
+ new NotifBindPipelineLogger(logcatLogBuffer()),
mTestLooper.getLooper());
mBindPipeline.setStage(mBindStage);
@@ -596,7 +597,7 @@
mock(NotificationGutsManager.class),
mDismissibilityProvider,
mock(MetricsLogger.class),
- mock(NotificationChildrenContainerLogger.class),
+ new NotificationChildrenContainerLogger(logcatLogBuffer()),
mock(SmartReplyConstants.class),
mock(SmartReplyController.class),
mFeatureFlags,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java
index 7c99568..32f0fe7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.row;
+import static com.android.systemui.dump.LogBufferHelperKt.logcatLogBuffer;
import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_ALL;
import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED;
import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_EXPANDED;
@@ -68,7 +69,7 @@
mRowContentBindStage = new RowContentBindStage(
mBinder,
mock(NotifInflationErrorManager.class),
- mock(RowContentBindStageLogger.class));
+ new RowContentBindStageLogger(logcatLogBuffer()));
mRowContentBindStage.createStageParams(mEntry);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
index 07eadf7c..6f431be 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.stack;
+import static com.android.systemui.dump.LogBufferHelperKt.logcatLogBuffer;
import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
import static com.android.systemui.statusbar.StatusBarState.SHADE;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL;
@@ -154,8 +155,10 @@
@Mock private VisibilityLocationProviderDelegator mVisibilityLocationProviderDelegator;
@Mock private ShadeController mShadeController;
@Mock private InteractionJankMonitor mJankMonitor;
- @Mock private StackStateLogger mStackLogger;
- @Mock private NotificationStackScrollLogger mLogger;
+ private final StackStateLogger mStackLogger = new StackStateLogger(logcatLogBuffer(),
+ logcatLogBuffer());
+ private final NotificationStackScrollLogger mLogger = new NotificationStackScrollLogger(
+ logcatLogBuffer(), logcatLogBuffer(), logcatLogBuffer());
@Mock private NotificationStackSizeCalculator mNotificationStackSizeCalculator;
@Mock private NotificationTargetsHelper mNotificationTargetsHelper;
@Mock private SecureSettings mSecureSettings;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
index 6fda56c..72522ca 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.phone;
+import static com.android.systemui.dump.LogBufferHelperKt.logcatLogBuffer;
+
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
@@ -30,6 +32,7 @@
import androidx.test.filters.SmallTest;
import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.R;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shade.ShadeExpansionStateManager;
import com.android.systemui.statusbar.AlertingNotificationManager;
@@ -61,7 +64,8 @@
private HeadsUpManagerPhone mHeadsUpManager;
- @Mock private HeadsUpManagerLogger mHeadsUpManagerLogger;
+ private final HeadsUpManagerLogger mHeadsUpManagerLogger = new HeadsUpManagerLogger(
+ logcatLogBuffer());
@Mock private GroupMembershipManager mGroupManager;
@Mock private VisualStabilityProvider mVSProvider;
@Mock private StatusBarStateController mStatusBarStateController;
@@ -104,11 +108,13 @@
}
}
+ @Override
protected AlertingNotificationManager createAlertingNotificationManager() {
return mHeadsUpManager;
}
@Before
+ @Override
public void setUp() {
AccessibilityManagerWrapper accessibilityMgr =
mDependency.injectMockDependency(AccessibilityManagerWrapper.class);
@@ -116,8 +122,10 @@
.thenReturn(TEST_AUTO_DISMISS_TIME);
when(mVSProvider.isReorderingAllowed()).thenReturn(true);
mDependency.injectMockDependency(NotificationShadeWindowController.class);
- super.setUp();
+ mContext.getOrCreateTestableResources().addOverride(
+ R.integer.ambient_notification_extension_time, 500);
+ super.setUp();
mHeadsUpManager = new TestableHeadsUpManagerPhone(
mContext,
mHeadsUpManagerLogger,
@@ -134,8 +142,9 @@
}
@After
+ @Override
public void tearDown() {
- mTestHandler.removeCallbacksAndMessages(null);
+ super.tearDown();
}
@Test
@@ -181,7 +190,6 @@
assertTrue(mHeadsUpManager.canRemoveImmediately(mEntry.getKey()));
}
-
@Test
public void testExtendHeadsUp() {
mHeadsUpManager.showNotification(mEntry);
@@ -189,7 +197,7 @@
() -> mLivesPastNormalTime = mHeadsUpManager.isAlerting(mEntry.getKey());
mTestHandler.postDelayed(pastNormalTimeRunnable,
TEST_AUTO_DISMISS_TIME + mHeadsUpManager.mExtensionTime / 2);
- mTestHandler.postDelayed(TEST_TIMEOUT_RUNNABLE, TEST_TIMEOUT_TIME);
+ mTestHandler.postDelayed(mTestTimeoutRunnable, TEST_TIMEOUT_TIME);
mHeadsUpManager.extendHeadsUp();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index 33144f2..08a76ef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -20,6 +20,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.systemui.dump.LogBufferHelperKt.logcatLogBuffer;
import static com.google.common.truth.Truth.assertThat;
@@ -42,6 +43,7 @@
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
+import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ResolveInfo;
import android.os.Handler;
@@ -248,7 +250,7 @@
mock(StatusBarRemoteInputCallback.class),
mActivityIntentHelper,
mock(MetricsLogger.class),
- mock(StatusBarNotificationActivityStarterLogger.class),
+ new StatusBarNotificationActivityStarterLogger(logcatLogBuffer()),
mOnUserInteractionCallback,
mock(NotificationPresenter.class),
mock(ShadeViewController.class),
@@ -410,10 +412,12 @@
@Test
public void testOnFullScreenIntentWhenDozing_wakeUpDevice() {
// GIVEN entry that can has a full screen intent that can show
+ PendingIntent fullScreenIntent = PendingIntent.getActivity(mContext, 1,
+ new Intent("fake_full_screen"), PendingIntent.FLAG_IMMUTABLE);
Notification.Builder nb = new Notification.Builder(mContext, "a")
.setContentTitle("foo")
.setSmallIcon(android.R.drawable.sym_def_app_icon)
- .setFullScreenIntent(mock(PendingIntent.class), true);
+ .setFullScreenIntent(fullScreenIntent, true);
StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0,
"tag" + System.currentTimeMillis(), 0, 0,
nb.build(), new UserHandle(0), null, 0);
@@ -437,6 +441,7 @@
// GIVEN entry that can has a full screen intent that can show
PendingIntent mockFullScreenIntent = mock(PendingIntent.class);
when(mockFullScreenIntent.getCreatorUid()).thenReturn(kTestUid);
+ when(mockFullScreenIntent.getIntent()).thenReturn(new Intent("fake_full_screen"));
ResolveInfo resolveInfo = new ResolveInfo();
resolveInfo.activityInfo = new ActivityInfo();
resolveInfo.activityInfo.name = kTestActivityName;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
index a797e03..14edf3d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.policy;
+import static com.android.systemui.dump.LogBufferHelperKt.logcatLogBuffer;
+
import static com.google.common.truth.Truth.assertThat;
import static junit.framework.Assert.assertEquals;
@@ -26,6 +28,7 @@
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -70,7 +73,7 @@
@Mock private NotificationEntry mEntry;
@Mock private StatusBarNotification mSbn;
@Mock private Notification mNotification;
- @Mock private HeadsUpManagerLogger mLogger;
+ private final HeadsUpManagerLogger mLogger = spy(new HeadsUpManagerLogger(logcatLogBuffer()));
@Mock private AccessibilityManagerWrapper mAccessibilityMgr;
private final class TestableHeadsUpManager extends HeadsUpManager {
@@ -86,14 +89,17 @@
}
}
+ @Override
protected AlertingNotificationManager createAlertingNotificationManager() {
return mHeadsUpManager;
}
@Before
+ @Override
public void setUp() {
initMocks(this);
when(mEntry.getSbn()).thenReturn(mSbn);
+ when(mEntry.getKey()).thenReturn("entryKey");
when(mSbn.getNotification()).thenReturn(mNotification);
super.setUp();
mHeadsUpManager = new TestableHeadsUpManager(mContext, mLogger, mTestHandler,
@@ -101,8 +107,9 @@
}
@After
+ @Override
public void tearDown() {
- mTestHandler.removeCallbacksAndMessages(null);
+ super.tearDown();
}
@Test
@@ -169,7 +176,7 @@
() -> mLivesPastNormalTime = mHeadsUpManager.isAlerting(mEntry.getKey());
mTestHandler.postDelayed(pastNormalTimeRunnable,
(TEST_A11Y_AUTO_DISMISS_TIME + TEST_AUTO_DISMISS_TIME) / 2);
- mTestHandler.postDelayed(TEST_TIMEOUT_RUNNABLE, TEST_A11Y_TIMEOUT_TIME);
+ mTestHandler.postDelayed(mTestTimeoutRunnable, TEST_A11Y_TIMEOUT_TIME);
TestableLooper.get(this).processMessages(2);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java b/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java
index f299ad4..7593e84 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java
@@ -18,6 +18,8 @@
import static android.view.accessibility.AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED;
+import static com.android.systemui.dump.LogBufferHelperKt.logcatLogBuffer;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -63,7 +65,6 @@
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.PluginManager;
import com.android.systemui.statusbar.CommandQueue;
@@ -110,8 +111,7 @@
@Mock private IAccessibilityManager mAccessibilityManager;
@Mock private PluginManager mPluginManager;
@Mock private DumpManager mDumpManager;
- @Mock private ToastLogger mToastLogger;
- @Mock private FeatureFlags mFeatureFlags;
+ private final ToastLogger mToastLogger = spy(new ToastLogger(logcatLogBuffer()));
@Mock private PackageManager mPackageManager;
@Mock private ITransientNotificationCallback mCallback;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt
index bf54d42..aa49287 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt
@@ -20,6 +20,7 @@
import android.content.res.Configuration
import android.content.res.Resources
import android.os.Handler
+import android.os.Looper
import android.testing.AndroidTestingRunner
import androidx.core.util.Consumer
import androidx.test.filters.SmallTest
@@ -38,6 +39,7 @@
import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
+import junit.framework.Assert.fail
import java.util.concurrent.Executor
import org.junit.Before
import org.junit.Test
@@ -55,16 +57,20 @@
@Mock private lateinit var activityTypeProvider: ActivityManagerActivityTypeProvider
- @Mock private lateinit var handler: Handler
-
@Mock private lateinit var rotationChangeProvider: RotationChangeProvider
@Mock private lateinit var unfoldKeyguardVisibilityProvider: UnfoldKeyguardVisibilityProvider
@Mock private lateinit var resources: Resources
+ @Mock private lateinit var handler: Handler
+
+ @Mock private lateinit var mainLooper: Looper
+
@Mock private lateinit var context: Context
+ @Mock private lateinit var thread: Thread
+
@Captor private lateinit var rotationListener: ArgumentCaptor<RotationListener>
private val foldProvider = TestFoldProvider()
@@ -89,6 +95,11 @@
override val halfFoldedTimeoutMillis: Int
get() = HALF_OPENED_TIMEOUT_MILLIS.toInt()
}
+ whenever(mainLooper.isCurrentThread).thenReturn(true)
+ whenever(handler.looper).thenReturn(mainLooper)
+ whenever(mainLooper.isCurrentThread).thenReturn(true)
+ whenever(mainLooper.thread).thenReturn(thread)
+ whenever(thread.name).thenReturn("backgroundThread")
whenever(context.resources).thenReturn(resources)
whenever(context.mainExecutor).thenReturn(mContext.mainExecutor)
@@ -435,6 +446,26 @@
}
@Test
+ fun startOnlyOnce_whenStartTriggeredThrice_startOnlyOnce() {
+ foldStateProvider.start()
+ foldStateProvider.start()
+ foldStateProvider.start()
+
+ assertThat(foldProvider.getNumberOfCallbacks()).isEqualTo(1)
+ }
+
+ @Test(expected = AssertionError::class)
+ fun startMethod_whileNotOnMainThread_throwsException() {
+ whenever(mainLooper.isCurrentThread).thenReturn(true)
+ try {
+ foldStateProvider.start()
+ fail("Should have thrown AssertionError: should be called from the main thread.")
+ } catch (e: AssertionError) {
+ assertThat(e.message).contains("backgroundThread")
+ }
+ }
+
+ @Test
fun startClosingEvent_whileNotOnKeyguard_triggersAfterThreshold() {
setKeyguardVisibility(visible = false)
setInitialHingeAngle(START_CLOSING_ON_APPS_THRESHOLD_DEGREES)
@@ -658,6 +689,10 @@
fun notifyFolded(isFolded: Boolean) {
callbacks.forEach { it.onFoldUpdated(isFolded) }
}
+
+ fun getNumberOfCallbacks(): Int{
+ return callbacks.size
+ }
}
private class TestScreenOnStatusProvider : ScreenStatusProvider {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/QuickAccessWalletControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/QuickAccessWalletControllerTest.java
index 8e4f184..53e5e7d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/QuickAccessWalletControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/QuickAccessWalletControllerTest.java
@@ -188,6 +188,25 @@
}
@Test
+ public void queryWalletCards_walletEnabled_queryMultipleCards() {
+ mController.queryWalletCards(mCardsRetriever, 5);
+
+ verify(mQuickAccessWalletClient)
+ .getWalletCards(
+ eq(MoreExecutors.directExecutor()), mRequestCaptor.capture(),
+ eq(mCardsRetriever));
+
+ GetWalletCardsRequest request = mRequestCaptor.getValue();
+ assertEquals(5, mRequestCaptor.getValue().getMaxCards());
+ assertEquals(
+ mContext.getResources().getDimensionPixelSize(R.dimen.wallet_tile_card_view_width),
+ request.getCardWidthPx());
+ assertEquals(
+ mContext.getResources().getDimensionPixelSize(R.dimen.wallet_tile_card_view_height),
+ request.getCardHeightPx());
+ }
+
+ @Test
public void queryWalletCards_walletFeatureNotAvailable_noQuery() {
when(mQuickAccessWalletClient.isWalletFeatureAvailable()).thenReturn(false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/WalletContextualSuggestionsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/WalletContextualSuggestionsControllerTest.kt
index 3901d72..d5bdb59 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/WalletContextualSuggestionsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/WalletContextualSuggestionsControllerTest.kt
@@ -215,7 +215,7 @@
cards: List<WalletCard> = emptyList(),
shouldFail: Boolean = false
) {
- whenever(walletController.queryWalletCards(any())).thenAnswer { invocation ->
+ whenever(walletController.queryWalletCards(any(), anyInt())).thenAnswer { invocation ->
with(
invocation.arguments[0] as QuickAccessWalletClient.OnWalletCardsRetrievedCallback
) {
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 26a75d0..6cffb66 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
@@ -92,6 +92,7 @@
)
}
}
+
private val context = test.context
fun fakeSceneContainerRepository(
@@ -119,9 +120,12 @@
)
}
- fun sceneInteractor(): SceneInteractor {
+ fun sceneInteractor(
+ repository: SceneContainerRepository = fakeSceneContainerRepository()
+ ): SceneInteractor {
return SceneInteractor(
- repository = fakeSceneContainerRepository(),
+ repository = repository,
+ logger = mock(),
)
}
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
index 8c5244e..6743515 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
@@ -62,6 +62,7 @@
private val hingeAngleListener = HingeAngleListener()
private val screenListener = ScreenStatusListener()
private val foldStateListener = FoldStateListener()
+ private val mainLooper = handler.looper
private val timeoutRunnable = Runnable { cancelAnimation() }
private val rotationListener = RotationListener {
if (isTransitionInProgress) cancelAnimation()
@@ -77,22 +78,28 @@
private var isFolded = false
private var isScreenOn = false
private var isUnfoldHandled = true
+ private var isStarted = false
override fun start() {
+ assertMainThread()
+ if (isStarted) return
foldProvider.registerCallback(foldStateListener, mainExecutor)
screenStatusProvider.addCallback(screenListener)
hingeAngleProvider.addCallback(hingeAngleListener)
rotationChangeProvider.addCallback(rotationListener)
activityTypeProvider.init()
+ isStarted = true
}
override fun stop() {
+ assertMainThread()
screenStatusProvider.removeCallback(screenListener)
foldProvider.unregisterCallback(foldStateListener)
hingeAngleProvider.removeCallback(hingeAngleListener)
hingeAngleProvider.stop()
rotationChangeProvider.removeCallback(rotationListener)
activityTypeProvider.uninit()
+ isStarted = false
}
override fun addCallback(listener: FoldUpdatesListener) {
@@ -292,6 +299,14 @@
onHingeAngle(angle)
}
}
+
+ private fun assertMainThread() {
+ check(mainLooper.isCurrentThread) {
+ ("should be called from the main thread." +
+ " sMainLooper.threadName=" + mainLooper.thread.name +
+ " Thread.currentThread()=" + Thread.currentThread().name)
+ }
+ }
}
fun @receiver:FoldUpdate Int.name() =
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index b76e99e..37abe1b 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -2404,6 +2404,7 @@
mLoggedInlineDatasetShown = true;
}
mService.logDatasetShown(this.id, mClientState, uiType);
+ Slog.d(TAG, "onShown(): " + uiType);
}
}
diff --git a/services/companion/java/com/android/server/companion/CompanionApplicationController.java b/services/companion/java/com/android/server/companion/CompanionApplicationController.java
index 5a9c470..c2d2468 100644
--- a/services/companion/java/com/android/server/companion/CompanionApplicationController.java
+++ b/services/companion/java/com/android/server/companion/CompanionApplicationController.java
@@ -44,8 +44,9 @@
* Manages communication with companion applications via
* {@link android.companion.ICompanionDeviceService} interface, including "connecting" (binding) to
* the services, maintaining the connection (the binding), and invoking callback methods such as
- * {@link CompanionDeviceService#onDeviceAppeared(AssociationInfo)} and
- * {@link CompanionDeviceService#onDeviceDisappeared(AssociationInfo)} in the application process.
+ * {@link CompanionDeviceService#onDeviceAppeared(AssociationInfo)},
+ * {@link CompanionDeviceService#onDeviceDisappeared(AssociationInfo)} and
+ * {@link CompanionDeviceService#onDeviceEvent(AssociationInfo, int)} in the application process.
*
* <p>
* The following is the list of the APIs provided by {@link CompanionApplicationController} (to be
@@ -53,8 +54,7 @@
* <ul>
* <li> {@link #bindCompanionApplication(int, String, boolean)}
* <li> {@link #unbindCompanionApplication(int, String)}
- * <li> {@link #notifyCompanionApplicationDeviceAppeared(AssociationInfo)}
- * <li> {@link #notifyCompanionApplicationDeviceDisappeared(AssociationInfo)}
+ * <li> {@link #notifyCompanionApplicationDeviceEvent(AssociationInfo, int)} (AssociationInfo, int)}
* <li> {@link #isCompanionApplicationBound(int, String)}
* <li> {@link #isRebindingCompanionApplicationScheduled(int, String)}
* </ul>
@@ -240,19 +240,16 @@
void notifyCompanionApplicationDeviceAppeared(AssociationInfo association) {
final int userId = association.getUserId();
final String packageName = association.getPackageName();
- if (DEBUG) {
- Log.i(TAG, "notifyDevice_Appeared() id=" + association.getId() + " u" + userId
+
+ Slog.i(TAG, "notifyDevice_Appeared() id=" + association.getId() + " u" + userId
+ "/" + packageName);
- }
final CompanionDeviceServiceConnector primaryServiceConnector =
getPrimaryServiceConnector(userId, packageName);
if (primaryServiceConnector == null) {
- if (DEBUG) {
- Log.e(TAG, "notify_CompanionApplicationDevice_Appeared(): "
+ Slog.e(TAG, "notify_CompanionApplicationDevice_Appeared(): "
+ "u" + userId + "/" + packageName + " is NOT bound.");
- Log.d(TAG, "Stacktrace", new Throwable());
- }
+ Slog.e(TAG, "Stacktrace", new Throwable());
return;
}
@@ -265,19 +262,16 @@
void notifyCompanionApplicationDeviceDisappeared(AssociationInfo association) {
final int userId = association.getUserId();
final String packageName = association.getPackageName();
- if (DEBUG) {
- Log.i(TAG, "notifyDevice_Disappeared() id=" + association.getId() + " u" + userId
- + "/" + packageName);
- }
+
+ Slog.i(TAG, "notifyDevice_Disappeared() id=" + association.getId() + " u" + userId
+ + "/" + packageName);
final CompanionDeviceServiceConnector primaryServiceConnector =
getPrimaryServiceConnector(userId, packageName);
if (primaryServiceConnector == null) {
- if (DEBUG) {
- Log.e(TAG, "notify_CompanionApplicationDevice_Disappeared(): "
+ Slog.e(TAG, "notify_CompanionApplicationDevice_Disappeared(): "
+ "u" + userId + "/" + packageName + " is NOT bound.");
- Log.d(TAG, "Stacktrace", new Throwable());
- }
+ Slog.e(TAG, "Stacktrace", new Throwable());
return;
}
@@ -287,6 +281,27 @@
primaryServiceConnector.postOnDeviceDisappeared(association);
}
+ void notifyCompanionApplicationDeviceEvent(AssociationInfo association, int event) {
+ final int userId = association.getUserId();
+ final String packageName = association.getPackageName();
+ final CompanionDeviceServiceConnector primaryServiceConnector =
+ getPrimaryServiceConnector(userId, packageName);
+
+ if (primaryServiceConnector == null) {
+ Slog.e(TAG, "notifyCompanionApplicationDeviceEvent(): "
+ + "u" + userId + "/" + packageName
+ + " event=[ " + event + " ] is NOT bound.");
+ Slog.e(TAG, "Stacktrace", new Throwable());
+ return;
+ }
+
+ Slog.i(TAG, "Calling onDeviceEvent() to userId=[" + userId + "] package=["
+ + packageName + "] associationId=[" + association.getId()
+ + "] state=[" + event + "]");
+
+ primaryServiceConnector.postOnDeviceEvent(association, event);
+ }
+
void dump(@NonNull PrintWriter out) {
out.append("Companion Device Application Controller: \n");
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 82d4d60..c5501f1 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -24,6 +24,12 @@
import static android.Manifest.permission.USE_COMPANION_TRANSPORTS;
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
import static android.companion.AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION;
+import static android.companion.CompanionDeviceService.DEVICE_EVENT_BLE_APPEARED;
+import static android.companion.CompanionDeviceService.DEVICE_EVENT_BLE_DISAPPEARED;
+import static android.companion.CompanionDeviceService.DEVICE_EVENT_BT_CONNECTED;
+import static android.companion.CompanionDeviceService.DEVICE_EVENT_BT_DISCONNECTED;
+import static android.companion.CompanionDeviceService.DEVICE_EVENT_SELF_MANAGED_APPEARED;
+import static android.companion.CompanionDeviceService.DEVICE_EVENT_SELF_MANAGED_DISAPPEARED;
import static android.content.pm.PackageManager.CERT_INPUT_SHA256;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Process.SYSTEM_UID;
@@ -383,17 +389,8 @@
if (!association.shouldBindWhenPresent()) return;
- final int userId = association.getUserId();
- final String packageName = association.getPackageName();
- // Set bindImportant to true when the association is self-managed to avoid the target
- // service being killed.
- final boolean bindImportant = association.isSelfManaged();
+ bindApplicationIfNeeded(association);
- if (!mCompanionAppController.isCompanionApplicationBound(userId, packageName)) {
- mCompanionAppController.bindCompanionApplication(userId, packageName, bindImportant);
- } else if (DEBUG) {
- Log.i(TAG, "u" + userId + "\\" + packageName + " is already bound");
- }
mCompanionAppController.notifyCompanionApplicationDeviceAppeared(association);
}
@@ -414,11 +411,57 @@
if (association.shouldBindWhenPresent()) {
mCompanionAppController.notifyCompanionApplicationDeviceDisappeared(association);
}
+ }
- // Check if there are other devices associated to the app that are present.
- if (shouldBindPackage(userId, packageName)) return;
+ private void onDeviceEventInternal(int associationId, int event) {
+ Slog.i(TAG, "onDeviceEventInternal() id=" + associationId + " event= " + event);
+ final AssociationInfo association = mAssociationStore.getAssociationById(associationId);
+ final String packageName = association.getPackageName();
+ final int userId = association.getUserId();
+ switch (event) {
+ case DEVICE_EVENT_BLE_APPEARED:
+ case DEVICE_EVENT_BT_CONNECTED:
+ case DEVICE_EVENT_SELF_MANAGED_APPEARED:
+ if (!association.shouldBindWhenPresent()) return;
- mCompanionAppController.unbindCompanionApplication(userId, packageName);
+ bindApplicationIfNeeded(association);
+
+ mCompanionAppController.notifyCompanionApplicationDeviceEvent(
+ association, event);
+ break;
+ case DEVICE_EVENT_BLE_DISAPPEARED:
+ case DEVICE_EVENT_BT_DISCONNECTED:
+ case DEVICE_EVENT_SELF_MANAGED_DISAPPEARED:
+ if (!mCompanionAppController.isCompanionApplicationBound(userId, packageName)) {
+ if (DEBUG) Log.w(TAG, "u" + userId + "\\" + packageName + " is NOT bound");
+ return;
+ }
+ if (association.shouldBindWhenPresent()) {
+ mCompanionAppController.notifyCompanionApplicationDeviceEvent(
+ association, event);
+ }
+ // Check if there are other devices associated to the app that are present.
+ if (shouldBindPackage(userId, packageName)) return;
+ mCompanionAppController.unbindCompanionApplication(userId, packageName);
+ break;
+ default:
+ Slog.e(TAG, "Event: " + event + "is not supported");
+ break;
+ }
+ }
+
+ private void bindApplicationIfNeeded(AssociationInfo association) {
+ final String packageName = association.getPackageName();
+ final int userId = association.getUserId();
+ // Set bindImportant to true when the association is self-managed to avoid the target
+ // service being killed.
+ final boolean bindImportant = association.isSelfManaged();
+ if (!mCompanionAppController.isCompanionApplicationBound(userId, packageName)) {
+ mCompanionAppController.bindCompanionApplication(
+ userId, packageName, bindImportant);
+ } else if (DEBUG) {
+ Log.i(TAG, "u" + userId + "\\" + packageName + " is already bound");
+ }
}
/**
@@ -883,7 +926,6 @@
+ " active=" + active
+ " deviceAddress=" + deviceAddress);
}
-
final int userId = getCallingUserId();
enforceCallerIsSystemOr(userId, packageName);
@@ -912,10 +954,17 @@
// an application sets/unsets the mNotifyOnDeviceNearby flag.
mAssociationStore.updateAssociation(association);
+ int associationId = association.getId();
// If device is already present, then trigger callback.
- if (active && mDevicePresenceMonitor.isDevicePresent(association.getId())) {
- if (DEBUG) Log.d(TAG, "Device is already present. Triggering callback.");
- onDeviceAppearedInternal(association.getId());
+ if (active && mDevicePresenceMonitor.isDevicePresent(associationId)) {
+ Slog.i(TAG, "Device is already present. Triggering callback.");
+ if (mDevicePresenceMonitor.isBlePresent(associationId)
+ || mDevicePresenceMonitor.isSimulatePresent(associationId)) {
+ onDeviceAppearedInternal(associationId);
+ onDeviceEventInternal(associationId, DEVICE_EVENT_BLE_APPEARED);
+ } else if (mDevicePresenceMonitor.isBtConnected(associationId)) {
+ onDeviceEventInternal(associationId, DEVICE_EVENT_BT_CONNECTED);
+ }
}
// If last listener is unregistered, then unbind application.
@@ -1380,6 +1429,11 @@
public void onDeviceDisappeared(int associationId) {
onDeviceDisappearedInternal(associationId);
}
+
+ @Override
+ public void onDeviceEvent(int associationId, int event) {
+ onDeviceEventInternal(associationId, event);
+ }
};
private final PackageMonitor mPackageMonitor = new PackageMonitor() {
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java b/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java
index 82628a6..928842c 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java
@@ -106,6 +106,11 @@
void postOnDeviceDisappeared(@NonNull AssociationInfo associationInfo) {
post(companionService -> companionService.onDeviceDisappeared(associationInfo));
}
+ void postOnDeviceEvent(@NonNull AssociationInfo associationInfo, int event) {
+ post(companionService -> companionService.onDeviceEvent(associationInfo, event));
+ }
+
+
/**
* Post "unbind" job, which will run *after* all previously posted jobs complete.
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
index 94cede8..d368b86 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
@@ -107,15 +107,10 @@
mService.loadAssociationsFromDisk();
break;
- case "simulate-device-appeared":
+ case "simulate-device-event":
associationId = getNextIntArgRequired();
- mDevicePresenceMonitor.simulateDeviceAppeared(associationId);
- break;
-
- case "simulate-device-disappeared":
- associationId = getNextIntArgRequired();
- mDevicePresenceMonitor.simulateDeviceDisappeared(associationId);
- break;
+ int event = getNextIntArgRequired();
+ mDevicePresenceMonitor.simulateDeviceEvent(associationId, event);
case "remove-inactive-associations": {
// This command should trigger the same "clean-up" job as performed by the
@@ -320,7 +315,9 @@
pw.println(" information from persistent storage. USE FOR DEBUGGING PURPOSES ONLY.");
pw.println(" USE FOR DEBUGGING AND/OR TESTING PURPOSES ONLY.");
- pw.println(" simulate-device-appeared ASSOCIATION_ID");
+ pw.println(" simulate-device-event ASSOCIATION_ID EVENT");
+ pw.println(" Simulate the companion device event changes:");
+ pw.println(" Case(0): ");
pw.println(" Make CDM act as if the given companion device has appeared.");
pw.println(" I.e. bind the associated companion application's");
pw.println(" CompanionDeviceService(s) and trigger onDeviceAppeared() callback.");
@@ -328,15 +325,17 @@
pw.println(" will act as if device disappeared, unless 'simulate-device-disappeared'");
pw.println(" or 'simulate-device-appeared' is called again before 60 seconds run out"
+ ".");
- pw.println(" USE FOR DEBUGGING AND/OR TESTING PURPOSES ONLY.");
-
- pw.println(" simulate-device-disappeared ASSOCIATION_ID");
+ pw.println(" Case(1): ");
pw.println(" Make CDM act as if the given companion device has disappeared.");
pw.println(" I.e. unbind the associated companion application's");
pw.println(" CompanionDeviceService(s) and trigger onDeviceDisappeared() callback.");
pw.println(" NOTE: This will only have effect if 'simulate-device-appeared' was");
pw.println(" invoked for the same device (same ASSOCIATION_ID) no longer than");
pw.println(" 60 seconds ago.");
+ pw.println(" Case(2): ");
+ pw.println(" Make CDM act as if the given companion device is BT connected ");
+ pw.println(" Case(3): ");
+ pw.println(" Make CDM act as if the given companion device is BT disconnected ");
pw.println(" USE FOR DEBUGGING AND/OR TESTING PURPOSES ONLY.");
pw.println(" remove-inactive-associations");
diff --git a/services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java b/services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java
index 0b2cce0..7e30790 100644
--- a/services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java
+++ b/services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java
@@ -56,7 +56,6 @@
import android.content.IntentFilter;
import android.os.Handler;
import android.os.Looper;
-import android.os.Message;
import android.util.Log;
import android.util.Slog;
@@ -73,20 +72,6 @@
class BleCompanionDeviceScanner implements AssociationStore.OnChangeListener {
private static final String TAG = "CDM_BleCompanionDeviceScanner";
- /**
- * When using {@link ScanSettings#SCAN_MODE_LOW_POWER}, it usually takes from 20 seconds to
- * 2 minutes for the BLE scanner to find advertisements sent from the same device.
- * On the other hand, {@link android.bluetooth.BluetoothAdapter.LeScanCallback} will report
- * {@link ScanSettings#CALLBACK_TYPE_MATCH_LOST MATCH_LOST} 10 sec after it finds the
- * advertisement for the first time (add reports
- * {@link ScanSettings#CALLBACK_TYPE_FIRST_MATCH FIRST_MATCH}).
- * To avoid constantly reporting {@link Callback#onBleCompanionDeviceFound(int) onDeviceFound()}
- * and {@link Callback#onBleCompanionDeviceLost(int) onDeviceLost()} (while the device is
- * actually present) to its clients, {@link BleCompanionDeviceScanner}, will add 1-minute delay
- * after it receives {@link ScanSettings#CALLBACK_TYPE_MATCH_LOST MATCH_LOST}.
- */
- private static final int NOTIFY_DEVICE_LOST_DELAY = 2 * 60 * 1000; // 2 Min.
-
interface Callback {
void onBleCompanionDeviceFound(int associationId);
@@ -95,7 +80,6 @@
private final @NonNull AssociationStore mAssociationStore;
private final @NonNull Callback mCallback;
- private final @NonNull MainThreadHandler mMainThreadHandler;
// Non-null after init().
private @Nullable BluetoothAdapter mBtAdapter;
@@ -108,7 +92,6 @@
@NonNull AssociationStore associationStore, @NonNull Callback callback) {
mAssociationStore = associationStore;
mCallback = callback;
- mMainThreadHandler = new MainThreadHandler();
}
@MainThread
@@ -146,7 +129,7 @@
if (Looper.getMainLooper().isCurrentThread()) {
restartScan();
} else {
- mMainThreadHandler.post(this::restartScan);
+ new Handler(Looper.getMainLooper()).post(this::restartScan);
}
}
@@ -182,11 +165,10 @@
}
@MainThread
- private void startScan() {
+ void startScan() {
enforceInitialized();
if (DEBUG) Log.i(TAG, "startScan()");
-
// This method should not be called if scan is already in progress.
if (mScanning) {
Slog.w(TAG, "Scan is already in progress.");
@@ -243,7 +225,7 @@
}
}
- private void stopScanIfNeeded() {
+ void stopScanIfNeeded() {
enforceInitialized();
if (DEBUG) Log.i(TAG, "stopScan()");
@@ -343,16 +325,11 @@
switch (callbackType) {
case CALLBACK_TYPE_FIRST_MATCH:
- if (mMainThreadHandler.hasNotifyDeviceLostMessages(device)) {
- mMainThreadHandler.removeNotifyDeviceLostMessages(device);
- return;
- }
-
notifyDeviceFound(device);
break;
case CALLBACK_TYPE_MATCH_LOST:
- mMainThreadHandler.sendNotifyDeviceLostDelayedMessage(device);
+ notifyDeviceLost(device);
break;
default:
@@ -370,36 +347,6 @@
}
};
- @SuppressLint("HandlerLeak")
- private class MainThreadHandler extends Handler {
- private static final int NOTIFY_DEVICE_LOST = 1;
-
- MainThreadHandler() {
- super(Looper.getMainLooper());
- }
-
- @Override
- public void handleMessage(@NonNull Message message) {
- if (message.what != NOTIFY_DEVICE_LOST) return;
-
- final BluetoothDevice device = (BluetoothDevice) message.obj;
- notifyDeviceLost(device);
- }
-
- void sendNotifyDeviceLostDelayedMessage(BluetoothDevice device) {
- final Message message = obtainMessage(NOTIFY_DEVICE_LOST, device);
- sendMessageDelayed(message, NOTIFY_DEVICE_LOST_DELAY);
- }
-
- boolean hasNotifyDeviceLostMessages(BluetoothDevice device) {
- return hasEqualMessages(NOTIFY_DEVICE_LOST, device);
- }
-
- void removeNotifyDeviceLostMessages(BluetoothDevice device) {
- removeEqualMessages(NOTIFY_DEVICE_LOST, device);
- }
- }
-
private static String nameForBtState(int state) {
return nameForState(state) + "(" + state + ")";
}
diff --git a/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java b/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java
index a5410e4..6ba85bd 100644
--- a/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java
+++ b/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java
@@ -169,6 +169,7 @@
}
for (AssociationInfo association : associations) {
+ if (!association.isNotifyOnDeviceNearby()) continue;
final int id = association.getId();
if (connected) {
mCallback.onBluetoothCompanionDeviceConnected(id);
diff --git a/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java b/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java
index f6e9415..f45a1c4 100644
--- a/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java
+++ b/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java
@@ -16,6 +16,12 @@
package com.android.server.companion.presence;
+import static android.companion.CompanionDeviceService.DEVICE_EVENT_BLE_APPEARED;
+import static android.companion.CompanionDeviceService.DEVICE_EVENT_BLE_DISAPPEARED;
+import static android.companion.CompanionDeviceService.DEVICE_EVENT_BT_CONNECTED;
+import static android.companion.CompanionDeviceService.DEVICE_EVENT_BT_DISCONNECTED;
+import static android.companion.CompanionDeviceService.DEVICE_EVENT_SELF_MANAGED_APPEARED;
+import static android.companion.CompanionDeviceService.DEVICE_EVENT_SELF_MANAGED_DISAPPEARED;
import static android.os.Process.ROOT_UID;
import static android.os.Process.SHELL_UID;
@@ -32,6 +38,7 @@
import android.os.Message;
import android.os.UserManager;
import android.util.Log;
+import android.util.Slog;
import android.util.SparseArray;
import com.android.server.companion.AssociationStore;
@@ -54,6 +61,7 @@
* <li> {@link #isDevicePresent(int)}
* <li> {@link Callback#onDeviceAppeared(int) Callback.onDeviceAppeared(int)}
* <li> {@link Callback#onDeviceDisappeared(int) Callback.onDeviceDisappeared(int)}
+ * <li> {@link Callback#onDeviceStateChanged(int, int)}}
* </ul>
*/
@SuppressLint("LongLogTag")
@@ -69,6 +77,9 @@
/** Invoked when a companion device no longer seen nearby or disconnects. */
void onDeviceDisappeared(int associationId);
+
+ /**Invoked when device has corresponding event changes. */
+ void onDeviceEvent(int associationId, int state);
}
private final @NonNull AssociationStore mAssociationStore;
@@ -127,6 +138,28 @@
}
/**
+ * @return whether the current device is BT connected and had already reported to the app.
+ */
+
+ public boolean isBtConnected(int associationId) {
+ return mConnectedBtDevices.contains(associationId);
+ }
+
+ /**
+ * @return whether the current device in BLE range and had already reported to the app.
+ */
+ public boolean isBlePresent(int associationId) {
+ return mNearbyBleDevices.contains(associationId);
+ }
+
+ /**
+ * @return whether the current device had been already reported by the simulator.
+ */
+ public boolean isSimulatePresent(int associationId) {
+ return mSimulated.contains(associationId);
+ }
+
+ /**
* Marks a "self-managed" device as connected.
*
* <p>
@@ -136,7 +169,8 @@
* {@link android.companion.CompanionDeviceManager#notifyDeviceAppeared(int) notifyDeviceAppeared()}
*/
public void onSelfManagedDeviceConnected(int associationId) {
- onDevicePresent(mReportedSelfManagedDevices, associationId, "application-reported");
+ onDeviceEvent(mReportedSelfManagedDevices,
+ associationId, DEVICE_EVENT_SELF_MANAGED_APPEARED);
}
/**
@@ -149,45 +183,53 @@
* {@link android.companion.CompanionDeviceManager#notifyDeviceDisappeared(int) notifyDeviceDisappeared()}
*/
public void onSelfManagedDeviceDisconnected(int associationId) {
- onDeviceGone(mReportedSelfManagedDevices, associationId, "application-reported");
+ onDeviceEvent(mReportedSelfManagedDevices,
+ associationId, DEVICE_EVENT_SELF_MANAGED_DISAPPEARED);
}
/**
* Marks a "self-managed" device as disconnected when binderDied.
*/
public void onSelfManagedDeviceReporterBinderDied(int associationId) {
- onDeviceGone(mReportedSelfManagedDevices, associationId, "application-reported");
+ onDeviceEvent(mReportedSelfManagedDevices,
+ associationId, DEVICE_EVENT_SELF_MANAGED_DISAPPEARED);
}
@Override
public void onBluetoothCompanionDeviceConnected(int associationId) {
- onDevicePresent(mConnectedBtDevices, associationId, /* sourceLoggingTag */ "bt");
+ Slog.i(TAG, "onBluetoothCompanionDeviceConnected: "
+ + "associationId( " + associationId + " )");
+ onDeviceEvent(mConnectedBtDevices, associationId, DEVICE_EVENT_BT_CONNECTED);
+ // Stop scanning for BLE devices when this device is connected
+ // and there are no other devices to connect to.
+ if (canStopBleScan()) {
+ mBleScanner.stopScanIfNeeded();
+ }
}
@Override
public void onBluetoothCompanionDeviceDisconnected(int associationId) {
- // If disconnected device is also a BLE device, skip the 2-minute timer and mark it as gone.
- boolean isConnectableBleDevice = mNearbyBleDevices.remove(associationId);
- if (DEBUG && isConnectableBleDevice) {
- Log.d(TAG, "Bluetooth device disconnect was detected."
- + " Pre-emptively marking the BLE device as lost.");
- }
- onDeviceGone(mConnectedBtDevices, associationId, /* sourceLoggingTag */ "bt");
+ Slog.i(TAG, "onBluetoothCompanionDeviceDisconnected "
+ + "associationId( " + associationId + " )");
+ // Start BLE scanning when the device is disconnected.
+ mBleScanner.startScan();
+
+ onDeviceEvent(mConnectedBtDevices, associationId, DEVICE_EVENT_BT_DISCONNECTED);
}
@Override
public void onBleCompanionDeviceFound(int associationId) {
- onDevicePresent(mNearbyBleDevices, associationId, /* sourceLoggingTag */ "ble");
+ onDeviceEvent(mNearbyBleDevices, associationId, DEVICE_EVENT_BLE_APPEARED);
}
@Override
public void onBleCompanionDeviceLost(int associationId) {
- onDeviceGone(mNearbyBleDevices, associationId, /* sourceLoggingTag */ "ble");
+ onDeviceEvent(mNearbyBleDevices, associationId, DEVICE_EVENT_BLE_DISAPPEARED);
}
/** FOR DEBUGGING AND/OR TESTING PURPOSES ONLY. */
@TestApi
- public void simulateDeviceAppeared(int associationId) {
+ public void simulateDeviceEvent(int associationId, int state) {
// IMPORTANT: this API should only be invoked via the
// 'companiondevice simulate-device-appeared' Shell command, so the only uid-s allowed to
// make this call are SHELL and ROOT.
@@ -196,25 +238,32 @@
// Make sure the association exists.
enforceAssociationExists(associationId);
- onDevicePresent(mSimulated, associationId, /* sourceLoggingTag */ "simulated");
+ switch (state) {
+ case DEVICE_EVENT_BLE_APPEARED:
+ simulateDeviceAppeared(associationId, state);
+ break;
+ case DEVICE_EVENT_BT_CONNECTED:
+ onBluetoothCompanionDeviceConnected(associationId);
+ break;
+ case DEVICE_EVENT_BLE_DISAPPEARED:
+ simulateDeviceDisappeared(associationId, state);
+ break;
+ case DEVICE_EVENT_BT_DISCONNECTED:
+ onBluetoothCompanionDeviceDisconnected(associationId);
+ break;
+ default:
+ throw new IllegalArgumentException("State: " + state + "is not supported");
+ }
+ }
+ private void simulateDeviceAppeared(int associationId, int state) {
+ onDeviceEvent(mSimulated, associationId, state);
mSchedulerHelper.scheduleOnDeviceGoneCallForSimulatedDevicePresence(associationId);
}
- /** FOR DEBUGGING AND/OR TESTING PURPOSES ONLY. */
- @TestApi
- public void simulateDeviceDisappeared(int associationId) {
- // IMPORTANT: this API should only be invoked via the
- // 'companiondevice simulate-device-appeared' Shell command, so the only uid-s allowed to
- // make this call are SHELL and ROOT.
- // No other caller (including SYSTEM!) should be allowed.
- enforceCallerShellOrRoot();
- // Make sure the association exists.
- enforceAssociationExists(associationId);
-
+ private void simulateDeviceDisappeared(int associationId, int state) {
mSchedulerHelper.unscheduleOnDeviceGoneCallForSimulatedDevicePresence(associationId);
-
- onDeviceGone(mSimulated, associationId, /* sourceLoggingTag */ "simulated");
+ onDeviceEvent(mSimulated, associationId, state);
}
private void enforceAssociationExists(int associationId) {
@@ -224,58 +273,59 @@
}
}
- private void onDevicePresent(@NonNull Set<Integer> presentDevicesForSource,
- int newDeviceAssociationId, @NonNull String sourceLoggingTag) {
- if (DEBUG) {
- Log.i(TAG, "onDevice_Present() id=" + newDeviceAssociationId
- + ", source=" + sourceLoggingTag);
- Log.d(TAG, " > association="
- + mAssociationStore.getAssociationById(newDeviceAssociationId));
+ private void onDeviceEvent(@NonNull Set<Integer> presentDevicesForSource,
+ int associationId, int event) {
+ Slog.i(TAG, "onDeviceEvent() id=" + associationId + ", state=" + event);
+
+ switch (event) {
+ case DEVICE_EVENT_BLE_APPEARED:
+ case DEVICE_EVENT_BT_CONNECTED:
+ case DEVICE_EVENT_SELF_MANAGED_APPEARED:
+ final boolean alreadyPresent = isDevicePresent(associationId);
+ final boolean added = presentDevicesForSource.add(associationId);
+ if (!added) {
+ Slog.w(TAG, "Association with id "
+ + associationId + " is ALREADY reported as "
+ + "present by this source, event=" + event);
+ return;
+ }
+ // For backward compatibility, do not send the onDeviceAppeared() callback
+ // if it already reported BLE device status.
+ if (event == DEVICE_EVENT_BT_CONNECTED && alreadyPresent) {
+ Slog.i(TAG, "Ignore sending onDeviceAppeared callback, "
+ + "device id (" + associationId + ") already present.");
+ } else {
+ mCallback.onDeviceAppeared(associationId);
+ }
+
+ break;
+ case DEVICE_EVENT_BLE_DISAPPEARED:
+ case DEVICE_EVENT_BT_DISCONNECTED:
+ case DEVICE_EVENT_SELF_MANAGED_DISAPPEARED:
+ final boolean removed = presentDevicesForSource.remove(associationId);
+ if (!removed) {
+ Log.w(TAG, "Association with id " + associationId + " was NOT reported "
+ + "as present by this source, event= " + event);
+
+ return;
+ }
+ final boolean stillPresent = isDevicePresent(associationId);
+ // For backward compatibility, do not send the onDeviceDisappeared()
+ // callback when ble scan still presenting.
+ if (stillPresent) {
+ Slog.i(TAG, "Ignore sending onDeviceDisappeared callback, "
+ + "device id (" + associationId + ") is still present.");
+ } else {
+ mCallback.onDeviceDisappeared(associationId);
+ }
+
+ break;
+ default:
+ Slog.e(TAG, "Event: " + event + " is not supported");
+ return;
}
- final boolean alreadyPresent = isDevicePresent(newDeviceAssociationId);
- if (alreadyPresent) {
- Log.i(TAG, "Device" + "id (" + newDeviceAssociationId + ") already present.");
- }
-
- final boolean added = presentDevicesForSource.add(newDeviceAssociationId);
- if (!added) {
- Log.w(TAG, "Association with id "
- + newDeviceAssociationId + " is ALREADY reported as "
- + "present by this source (" + sourceLoggingTag + ")");
- }
-
- if (alreadyPresent) return;
-
- mCallback.onDeviceAppeared(newDeviceAssociationId);
- }
-
- private void onDeviceGone(@NonNull Set<Integer> presentDevicesForSource,
- int goneDeviceAssociationId, @NonNull String sourceLoggingTag) {
- if (DEBUG) {
- Log.i(TAG, "onDevice_Gone() id=" + goneDeviceAssociationId
- + ", source=" + sourceLoggingTag);
- Log.d(TAG, " > association="
- + mAssociationStore.getAssociationById(goneDeviceAssociationId));
- }
-
- final boolean removed = presentDevicesForSource.remove(goneDeviceAssociationId);
- if (!removed) {
- Log.w(TAG, "Association with id " + goneDeviceAssociationId + " was NOT reported "
- + "as present by this source (" + sourceLoggingTag + ")");
-
- return;
- }
-
- final boolean stillPresent = isDevicePresent(goneDeviceAssociationId);
- if (stillPresent) {
- if (DEBUG) {
- Log.i(TAG, " Device id (" + goneDeviceAssociationId + ") is still present.");
- }
- return;
- }
-
- mCallback.onDeviceDisappeared(goneDeviceAssociationId);
+ mCallback.onDeviceEvent(associationId, event);
}
/**
@@ -316,6 +366,19 @@
throw new SecurityException("Caller is neither Shell nor Root");
}
+ private boolean canStopBleScan() {
+ for (AssociationInfo ai : mAssociationStore.getAssociations()) {
+ int id = ai.getId();
+ // The BLE scan cannot be stopped if there's a device is not yet connected.
+ if (ai.isNotifyOnDeviceNearby() && !isBtConnected(id)) {
+ Slog.i(TAG, "The BLE scan cannot be stopped, "
+ + "device( " + id + " ) is not yet connected");
+ return false;
+ }
+ }
+ return true;
+ }
+
/**
* Dumps system information about devices that are marked as "present".
*/
@@ -386,7 +449,7 @@
public void handleMessage(@NonNull Message msg) {
final int associationId = msg.what;
if (mSimulated.contains(associationId)) {
- onDeviceGone(mSimulated, associationId, /* sourceLoggingTag */ "simulated");
+ onDeviceEvent(mSimulated, associationId, DEVICE_EVENT_BLE_DISAPPEARED);
}
}
}
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 459e24d..9f263c8 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -187,6 +187,7 @@
"ImmutabilityAnnotation",
"securebox",
"apache-commons-math",
+ "power_optimization_flags_lib",
],
javac_shard_size: 50,
javacflags: [
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 383bb25..da2588b 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -2414,7 +2414,7 @@
// Even if the service is already a FGS, we need to update the notification,
// so we need to call it again.
signalForegroundServiceObserversLocked(r);
- r.postNotification();
+ r.postNotification(true);
if (r.app != null) {
updateServiceForegroundLocked(psr, true);
}
@@ -2472,7 +2472,7 @@
} else if (r.appInfo.targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) {
// if it's been deferred, force to visibility
if (!r.mFgsNotificationShown) {
- r.postNotification();
+ r.postNotification(false);
}
dropFgsNotificationStateLocked(r);
if ((flags & Service.STOP_FOREGROUND_DETACH) != 0) {
@@ -2916,7 +2916,7 @@
// in the interval, so we lazy check whether we still need to show
// the notification.
if (r.isForeground && r.app != null) {
- r.postNotification();
+ r.postNotification(true);
r.mFgsNotificationShown = true;
} else {
if (DEBUG_FOREGROUND_SERVICE) {
@@ -5340,7 +5340,7 @@
thread.scheduleCreateService(r, r.serviceInfo,
null /* compatInfo (unused but need to keep method signature) */,
app.mState.getReportedProcState());
- r.postNotification();
+ r.postNotification(false);
created = true;
} catch (DeadObjectException e) {
Slog.w(TAG, "Application dead when creating service " + r);
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 9026c20..b7fc484 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -109,6 +109,7 @@
import com.android.server.Watchdog;
import com.android.server.net.BaseNetworkObserver;
import com.android.server.pm.UserManagerInternal;
+import com.android.server.power.optimization.Flags;
import com.android.server.power.stats.BatteryExternalStatsWorker;
import com.android.server.power.stats.BatteryStatsImpl;
import com.android.server.power.stats.BatteryUsageStatsProvider;
@@ -2605,6 +2606,10 @@
awaitCompletion();
synchronized (mStats) {
mStats.dumpConstantsLocked(pw);
+
+ pw.println("Flags:");
+ pw.println(" " + Flags.FLAG_STREAMLINED_BATTERY_STATS
+ + ": " + Flags.streamlinedBatteryStats());
}
}
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index cc9628f..1a58556 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -238,7 +238,7 @@
private static final String ATRACE_COMPACTION_TRACK = "Compaction";
private static final String ATRACE_FREEZER_TRACK = "Freezer";
- private static final int FREEZE_BINDER_TIMEOUT_MS = 100;
+ private static final int FREEZE_BINDER_TIMEOUT_MS = 0;
private static final int FREEZE_DEADLOCK_TIMEOUT_MS = 1000;
// If enabled, any compaction issued will apply to code mappings and share memory mappings.
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index aabab61..f7bbc8b 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -1324,7 +1324,7 @@
});
}
- public void postNotification() {
+ public void postNotification(boolean byForegroundService) {
if (isForeground && foregroundNoti != null && app != null) {
final int appUid = appInfo.uid;
final int appPid = app.getPid();
@@ -1432,7 +1432,7 @@
}
nm.enqueueNotification(localPackageName, localPackageName,
appUid, appPid, null, localForegroundId, localForegroundNoti,
- userId);
+ userId, byForegroundService /* byForegroundService */);
foregroundNoti = localForegroundNoti; // save it for amending next time
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index 9db9e77..0e4465d 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -87,6 +87,7 @@
DeviceConfig.NAMESPACE_CAMERA_NATIVE,
DeviceConfig.NAMESPACE_CONFIGURATION,
DeviceConfig.NAMESPACE_CONNECTIVITY,
+ DeviceConfig.NAMESPACE_CORE_EXPERIMENTS_TEAM_INTERNAL,
DeviceConfig.NAMESPACE_EDGETPU_NATIVE,
DeviceConfig.NAMESPACE_INPUT_NATIVE_BOOT,
DeviceConfig.NAMESPACE_INTELLIGENCE_CONTENT_SUGGESTIONS,
diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java
index f8f0088..df16c5b 100644
--- a/services/core/java/com/android/server/camera/CameraServiceProxy.java
+++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java
@@ -1015,6 +1015,12 @@
handles.add(id);
}
+ // If the device is running in headless system user mode then allow
+ // User 0 to access camera.
+ if (UserManager.isHeadlessSystemUserMode()) {
+ handles.add(UserHandle.USER_SYSTEM);
+ }
+
return handles;
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerInternal.java b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
index 919fc71..c240bcb 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerInternal.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
@@ -27,6 +27,9 @@
NotificationChannelGroup getNotificationChannelGroup(String pkg, int uid, String channelId);
void enqueueNotification(String pkg, String basePkg, int callingUid, int callingPid,
String tag, int id, Notification notification, int userId);
+ void enqueueNotification(String pkg, String basePkg, int callingUid, int callingPid,
+ String tag, int id, Notification notification, int userId,
+ boolean byForegroundService);
void cancelNotification(String pkg, String basePkg, int callingUid, int callingPid,
String tag, int id, int userId);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 7452aab..009e097 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2531,7 +2531,8 @@
}
enqueueNotificationInternal(r.getSbn().getPackageName(), r.getSbn().getOpPkg(),
r.getSbn().getUid(), r.getSbn().getInitialPid(), r.getSbn().getTag(),
- r.getSbn().getId(), r.getSbn().getNotification(), userId, muteOnReturn);
+ r.getSbn().getId(), r.getSbn().getNotification(), userId, muteOnReturn,
+ false /* byForegroundService */);
} catch (Exception e) {
Slog.e(TAG, "Cannot un-snooze notification", e);
}
@@ -3526,7 +3527,8 @@
public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
Notification notification, int userId) throws RemoteException {
enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
- Binder.getCallingPid(), tag, id, notification, userId);
+ Binder.getCallingPid(), tag, id, notification, userId,
+ false /* byForegroundService */);
}
@Override
@@ -6092,7 +6094,7 @@
}
if (summaryRecord != null && checkDisqualifyingFeatures(userId, uid,
summaryRecord.getSbn().getId(), summaryRecord.getSbn().getTag(), summaryRecord,
- true)) {
+ true, false)) {
return summaryRecord;
}
}
@@ -6421,7 +6423,15 @@
public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
String tag, int id, Notification notification, int userId) {
enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
- userId);
+ userId, false /* byForegroundService */);
+ }
+
+ @Override
+ public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
+ String tag, int id, Notification notification, int userId,
+ boolean byForegroundService) {
+ enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
+ userId, byForegroundService);
}
@Override
@@ -6599,19 +6609,19 @@
void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
final int callingPid, final String tag, final int id, final Notification notification,
- int incomingUserId) {
+ int incomingUserId, boolean byForegroundService) {
enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
- incomingUserId, false);
+ incomingUserId, false /* postSilently */, byForegroundService);
}
void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
final int callingPid, final String tag, final int id, final Notification notification,
- int incomingUserId, boolean postSilently) {
+ int incomingUserId, boolean postSilently, boolean byForegroundService) {
PostNotificationTracker tracker = acquireWakeLockForPost(pkg, callingUid);
boolean enqueued = false;
try {
enqueued = enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id,
- notification, incomingUserId, postSilently, tracker);
+ notification, incomingUserId, postSilently, tracker, byForegroundService);
} finally {
if (!enqueued) {
tracker.cancel();
@@ -6642,10 +6652,10 @@
* @return True if we successfully processed the notification and handed off the task of
* enqueueing it to a background thread; false otherwise.
*/
- private boolean enqueueNotificationInternal(final String pkg, final String opPkg,
+ private boolean enqueueNotificationInternal(final String pkg, final String opPkg, //HUI
final int callingUid, final int callingPid, final String tag, final int id,
final Notification notification, int incomingUserId, boolean postSilently,
- PostNotificationTracker tracker) {
+ PostNotificationTracker tracker, boolean byForegroundService) {
if (DBG) {
Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
+ " notification=" + notification);
@@ -6791,7 +6801,7 @@
mPreferencesHelper.hasUserDemotedInvalidMsgApp(pkg, notificationUid));
if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r,
- r.getSbn().getOverrideGroupKey() != null)) {
+ r.getSbn().getOverrideGroupKey() != null, byForegroundService)) {
return false;
}
@@ -7211,7 +7221,7 @@
* Has side effects.
*/
boolean checkDisqualifyingFeatures(int userId, int uid, int id, String tag,
- NotificationRecord r, boolean isAutogroup) {
+ NotificationRecord r, boolean isAutogroup, boolean byForegroundService) {
Notification n = r.getNotification();
final String pkg = r.getSbn().getPackageName();
final boolean isSystemNotification =
@@ -7302,7 +7312,8 @@
if (n.isStyle(Notification.CallStyle.class)) {
boolean hasFullScreenIntent = n.fullScreenIntent != null;
boolean requestedFullScreenIntent = (n.flags & FLAG_FSI_REQUESTED_BUT_DENIED) != 0;
- if (!n.isFgsOrUij() && !hasFullScreenIntent && !requestedFullScreenIntent) {
+ if (!n.isFgsOrUij() && !hasFullScreenIntent && !requestedFullScreenIntent
+ && !byForegroundService) {
throw new IllegalArgumentException(r.getKey() + " Not posted."
+ " CallStyle notifications must be for a foreground service or"
+ " user initated job or use a fullScreenIntent.");
diff --git a/services/core/java/com/android/server/power/Android.bp b/services/core/java/com/android/server/power/Android.bp
new file mode 100644
index 0000000..1da9dd7
--- /dev/null
+++ b/services/core/java/com/android/server/power/Android.bp
@@ -0,0 +1,12 @@
+aconfig_declarations {
+ name: "power_optimization_flags",
+ package: "com.android.server.power.optimization",
+ srcs: [
+ "stats/*.aconfig",
+ ],
+}
+
+java_aconfig_library {
+ name: "power_optimization_flags_lib",
+ aconfig_declarations: "power_optimization_flags",
+}
diff --git a/services/core/java/com/android/server/power/stats/flags.aconfig b/services/core/java/com/android/server/power/stats/flags.aconfig
new file mode 100644
index 0000000..d61bebc
--- /dev/null
+++ b/services/core/java/com/android/server/power/stats/flags.aconfig
@@ -0,0 +1,8 @@
+package: "com.android.server.power.optimization"
+
+flag {
+ name: "streamlined_battery_stats"
+ namespace: "power_optimization"
+ description: "Feature flag for streamlined battery stats"
+ bug: "285646152"
+}
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index 270f7f0c..2fef092 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -2296,12 +2296,13 @@
}
private VibrationAttributes createVibrationAttributes(CommonOptions commonOptions) {
- final int flags =
- commonOptions.force ? VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY : 0;
+ // This will bypass user settings, Do Not Disturb and other interruption policies.
+ final int flags = commonOptions.force ? ATTRIBUTES_ALL_BYPASS_FLAGS : 0;
return new VibrationAttributes.Builder()
.setFlags(flags)
- // Used to apply Settings.System.HAPTIC_FEEDBACK_INTENSITY to scale effects.
- .setUsage(VibrationAttributes.USAGE_TOUCH)
+ // Used to allow vibrations when the adb shell process is running in background.
+ // This will apply the NOTIFICATION_VIBRATION_INTENSITY setting.
+ .setUsage(VibrationAttributes.USAGE_COMMUNICATION_REQUEST)
.build();
}
diff --git a/services/core/java/com/android/server/wm/Dimmer.java b/services/core/java/com/android/server/wm/Dimmer.java
index d7667d8..4f3ab8b 100644
--- a/services/core/java/com/android/server/wm/Dimmer.java
+++ b/services/core/java/com/android/server/wm/Dimmer.java
@@ -349,7 +349,8 @@
// Otherwise use the same duration as the animation on the WindowContainer
AnimationAdapter animationAdapter = container.mSurfaceAnimator.getAnimation();
- return animationAdapter == null ? DEFAULT_DIM_ANIM_DURATION
+ final float durationScale = container.mWmService.getTransitionAnimationScaleLocked();
+ return animationAdapter == null ? (long) (DEFAULT_DIM_ANIM_DURATION * durationScale)
: animationAdapter.getDurationHint();
}
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 99cbdde..70edf3a 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -303,8 +303,7 @@
mOrientationListener.setCurrentRotation(mRotation);
mSettingsObserver = new SettingsObserver(uiHandler);
mSettingsObserver.observe();
- if (mSupportAutoRotation && mContext.getResources().getBoolean(
- R.bool.config_windowManagerHalfFoldAutoRotateOverride)) {
+ if (mSupportAutoRotation && isFoldable(mContext)) {
mFoldController = new FoldController();
} else {
mFoldController = null;
@@ -314,6 +313,10 @@
}
}
+ private static boolean isFoldable(Context context) {
+ return context.getResources().getIntArray(R.array.config_foldedDeviceStates).length > 0;
+ }
+
@VisibleForTesting
@Nullable
DisplayRotationImmersiveAppCompatPolicy initImmersiveAppCompatPolicy(
@@ -1469,11 +1472,6 @@
return false;
}
- // Do not show rotation choice when fold controller blocks rotation sensor
- if (mFoldController != null && mFoldController.shouldIgnoreSensorRotation()) {
- return false;
- }
-
// Don't show rotation choice if we are in tabletop or book modes.
if (isTabletopAutoRotateOverrideEnabled()) return false;
@@ -1781,8 +1779,11 @@
private SensorEventListener mHingeAngleSensorEventListener;
private final Set<Integer> mTabletopRotations;
private final Runnable mActivityBoundsUpdateCallback;
+ private final boolean mAllowHalfFoldAutoRotationOverride;
FoldController() {
+ mAllowHalfFoldAutoRotationOverride = mContext.getResources().getBoolean(
+ R.bool.config_windowManagerHalfFoldAutoRotateOverride);
mTabletopRotations = new ArraySet<>();
int[] tabletop_rotations = mContext.getResources().getIntArray(
R.array.config_deviceTabletopRotations);
@@ -1900,12 +1901,14 @@
}
boolean overrideFrozenRotation() {
- return mDeviceState == DeviceStateController.DeviceState.HALF_FOLDED;
+ return mAllowHalfFoldAutoRotationOverride
+ && mDeviceState == DeviceStateController.DeviceState.HALF_FOLDED;
}
boolean shouldRevertOverriddenRotation() {
// When transitioning to open.
- return mDeviceState == DeviceStateController.DeviceState.OPEN
+ return mAllowHalfFoldAutoRotationOverride
+ && mDeviceState == DeviceStateController.DeviceState.OPEN
&& !mShouldIgnoreSensorRotation // Ignore if the hinge angle still moving
&& mInHalfFoldTransition
&& mDisplayContent.getRotationReversionController().isOverrideActive(
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 9c08c74..af770e2 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -56,6 +56,7 @@
import android.view.animation.Animation;
import android.window.ScreenCapture;
+import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.ProtoLogImpl;
import com.android.internal.protolog.common.ProtoLog;
@@ -91,10 +92,12 @@
private float mLastWallpaperZoomOut = 0;
private int mLastWallpaperDisplayOffsetX = Integer.MIN_VALUE;
private int mLastWallpaperDisplayOffsetY = Integer.MIN_VALUE;
- private final float mMaxWallpaperScale;
// Whether COMMAND_FREEZE was dispatched.
private boolean mLastFrozen = false;
+ private float mMinWallpaperScale;
+ private float mMaxWallpaperScale;
+
// This is set when we are waiting for a wallpaper to tell us it is done
// changing its scroll position.
private WindowState mWaitingOnWallpaper;
@@ -240,14 +243,16 @@
WallpaperController(WindowManagerService service, DisplayContent displayContent) {
mService = service;
mDisplayContent = displayContent;
+ mIsLockscreenLiveWallpaperEnabled =
+ SystemProperties.getBoolean("persist.wm.debug.lockscreen_live_wallpaper", true);
+
Resources resources = service.mContext.getResources();
- mMaxWallpaperScale =
- resources.getFloat(com.android.internal.R.dimen.config_wallpaperMaxScale);
+ mMinWallpaperScale =
+ resources.getFloat(com.android.internal.R.dimen.config_wallpaperMinScale);
+ mMaxWallpaperScale = resources.getFloat(R.dimen.config_wallpaperMaxScale);
mShouldOffsetWallpaperCenter =
resources.getBoolean(
com.android.internal.R.bool.config_offsetWallpaperToCenterOfLargestDisplay);
- mIsLockscreenLiveWallpaperEnabled =
- SystemProperties.getBoolean("persist.wm.debug.lockscreen_live_wallpaper", true);
}
void resetLargestDisplay(Display display) {
@@ -256,6 +261,16 @@
}
}
+ @VisibleForTesting
+ void setMinWallpaperScale(float minScale) {
+ mMinWallpaperScale = minScale;
+ }
+
+ @VisibleForTesting
+ void setMaxWallpaperScale(float maxScale) {
+ mMaxWallpaperScale = maxScale;
+ }
+
@VisibleForTesting void setShouldOffsetWallpaperCenter(boolean shouldOffset) {
mShouldOffsetWallpaperCenter = shouldOffset;
}
@@ -1010,8 +1025,8 @@
}
}
- private float zoomOutToScale(float zoom) {
- return MathUtils.lerp(1, mMaxWallpaperScale, 1 - zoom);
+ private float zoomOutToScale(float zoomOut) {
+ return MathUtils.lerp(mMinWallpaperScale, mMaxWallpaperScale, 1 - zoomOut);
}
void dump(PrintWriter pw, String prefix) {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 6b225fc..bdee99b 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -10244,7 +10244,7 @@
try {
mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), r.getSbn().getId(),
- r.getSbn().getTag(), r,false);
+ r.getSbn().getTag(), r, false, false);
fail("Allowed a contextual direct reply with an immutable intent to be posted");
} catch (IllegalArgumentException e) {
// good
@@ -10275,7 +10275,7 @@
r.applyAdjustments();
mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), r.getSbn().getId(),
- r.getSbn().getTag(), r,false);
+ r.getSbn().getTag(), r, false, false);
}
@Test
@@ -10309,7 +10309,7 @@
r.applyAdjustments();
mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), r.getSbn().getId(),
- r.getSbn().getTag(), r,false);
+ r.getSbn().getTag(), r, false, false);
}
@Test
@@ -10522,7 +10522,7 @@
// normal blocked notifications - blocked
assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
- r.getSbn().getId(), r.getSbn().getTag(), r, false)).isFalse();
+ r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse();
// just using the style - blocked
nb.setStyle(new Notification.MediaStyle());
@@ -10531,7 +10531,7 @@
r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
- r.getSbn().getId(), r.getSbn().getTag(), r, false)).isFalse();
+ r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse();
// using the style, but incorrect type in session - blocked
nb.setStyle(new Notification.MediaStyle());
@@ -10543,7 +10543,7 @@
r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
- r.getSbn().getId(), r.getSbn().getTag(), r, false)).isFalse();
+ r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse();
// style + media session - bypasses block
nb.setStyle(new Notification.MediaStyle().setMediaSession(mock(MediaSession.Token.class)));
@@ -10552,7 +10552,7 @@
r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
- r.getSbn().getId(), r.getSbn().getTag(), r, false)).isTrue();
+ r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue();
}
@Test
@@ -10635,7 +10635,7 @@
// normal blocked notifications - blocked
assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
- r.getSbn().getId(), r.getSbn().getTag(), r, false)).isFalse();
+ r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse();
// just using the style - blocked
Person person = new Person.Builder()
@@ -10649,36 +10649,36 @@
r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
- r.getSbn().getId(), r.getSbn().getTag(), r, false)).isFalse();
+ r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse();
// style + managed call - bypasses block
when(mTelecomManager.isInManagedCall()).thenReturn(true);
assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
- r.getSbn().getId(), r.getSbn().getTag(), r, false)).isTrue();
+ r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue();
// style + self managed call - bypasses block
when(mTelecomManager.isInSelfManagedCall(
r.getSbn().getPackageName(), r.getUser())).thenReturn(true);
assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
- r.getSbn().getId(), r.getSbn().getTag(), r, false)).isTrue();
+ r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue();
// set telecom manager to null - blocked
mService.setTelecomManager(null);
assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
- r.getSbn().getId(), r.getSbn().getTag(), r, false))
+ r.getSbn().getId(), r.getSbn().getTag(), r, false, false))
.isFalse();
// set telecom feature to false - blocked
when(mPackageManagerClient.hasSystemFeature(FEATURE_TELECOM)).thenReturn(false);
assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
- r.getSbn().getId(), r.getSbn().getTag(), r, false))
+ r.getSbn().getId(), r.getSbn().getTag(), r, false, false))
.isFalse();
// telecom manager is not ready - blocked
mService.setTelecomManager(mTelecomManager);
when(mTelecomManager.isInCall()).thenThrow(new IllegalStateException("not ready"));
assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
- r.getSbn().getId(), r.getSbn().getTag(), r, false))
+ r.getSbn().getId(), r.getSbn().getTag(), r, false, false))
.isFalse();
}
@@ -11243,7 +11243,7 @@
try {
mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
- r.getSbn().getId(), r.getSbn().getTag(), r, false);
+ r.getSbn().getId(), r.getSbn().getTag(), r, false, false);
assertFalse("CallStyle should not be allowed without a valid use case", true);
} catch (IllegalArgumentException error) {
assertThat(error.getMessage()).contains("CallStyle");
@@ -11263,7 +11263,25 @@
NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
- r.getSbn().getId(), r.getSbn().getTag(), r, false)).isTrue();
+ r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue();
+ }
+
+ @Test
+ public void checkCallStyleNotification_allowedForByForegroundService() throws Exception {
+ Person person = new Person.Builder().setName("caller").build();
+ Notification n = new Notification.Builder(mContext, "test")
+ // Without FLAG_FOREGROUND_SERVICE.
+ //.setFlag(FLAG_FOREGROUND_SERVICE, true)
+ .setStyle(Notification.CallStyle.forOngoingCall(
+ person, mock(PendingIntent.class)))
+ .build();
+ StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0,
+ n, UserHandle.getUserHandleForUid(mUid), null, 0);
+ NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+ assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
+ r.getSbn().getId(), r.getSbn().getTag(), r, false,
+ true /* byForegroundService */)).isTrue();
}
@Test
@@ -11279,7 +11297,7 @@
NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
- r.getSbn().getId(), r.getSbn().getTag(), r, false)).isTrue();
+ r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue();
}
@Test
@@ -11295,7 +11313,7 @@
NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
- r.getSbn().getId(), r.getSbn().getTag(), r, false)).isTrue();
+ r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue();
}
@Test
@@ -11311,7 +11329,7 @@
NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
- r.getSbn().getId(), r.getSbn().getTag(), r, false)).isTrue();
+ r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue();
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/policy/ShortcutLoggingTests.java b/services/tests/wmtests/src/com/android/server/policy/ShortcutLoggingTests.java
index d6c821f..8fadecd 100644
--- a/services/tests/wmtests/src/com/android/server/policy/ShortcutLoggingTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/ShortcutLoggingTests.java
@@ -19,8 +19,7 @@
import android.platform.test.annotations.Presubmit;
import android.view.KeyEvent;
-import androidx.test.filters.FlakyTest;
-import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
import com.android.internal.annotations.Keep;
import com.android.server.input.KeyboardMetricsCollector.KeyboardLogEvent;
@@ -33,7 +32,7 @@
import junitparams.Parameters;
@Presubmit
-@LargeTest
+@MediumTest
@RunWith(JUnitParamsRunner.class)
public class ShortcutLoggingTests extends ShortcutKeyTestBase {
@@ -223,7 +222,7 @@
@Before
public void setUp() {
- setUpPhoneWindowManager();
+ setUpPhoneWindowManager(/*supportSettingsUpdate*/ true);
mPhoneWindowManager.overrideKeyEventSource(VENDOR_ID, PRODUCT_ID);
mPhoneWindowManager.overrideLaunchHome();
mPhoneWindowManager.overrideSearchKeyBehavior(
@@ -235,7 +234,6 @@
}
@Test
- @FlakyTest(bugId = 293273386)
@Parameters(method = "shortcutTestArguments")
public void testShortcuts(String testName, int[] testKeys, KeyboardLogEvent expectedLogEvent,
int expectedKey, int expectedModifierState) {
diff --git a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
index 7e7a9e1..ef3a6ed 100644
--- a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
+++ b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
@@ -185,11 +185,10 @@
mHandler = new Handler(mHandlerThread.getLooper());
mContext = mockingDetails(context).isSpy() ? context : spy(context);
mHandler.runWithScissors(() -> setUp(supportSettingsUpdate), 0 /* timeout */);
+ waitForIdle();
}
private void setUp(boolean supportSettingsUpdate) {
- mPhoneWindowManager = spy(new PhoneWindowManager());
-
// Use stubOnly() to reduce memory usage if it doesn't need verification.
final MockSettings spyStubOnly = withSettings().stubOnly()
.defaultAnswer(CALLS_REAL_METHODS);
@@ -200,6 +199,8 @@
.strictness(Strictness.LENIENT)
.startMocking();
+ mPhoneWindowManager = spy(new PhoneWindowManager());
+
doReturn(mWindowManagerInternal).when(
() -> LocalServices.getService(eq(WindowManagerInternal.class)));
doReturn(mActivityManagerInternal).when(
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
index 42422d9..939ff97 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
@@ -74,6 +74,7 @@
import androidx.annotation.Nullable;
import androidx.test.filters.SmallTest;
+import com.android.internal.R;
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.server.LocalServices;
import com.android.server.UiThread;
@@ -880,6 +881,33 @@
SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0));
}
+ @Test
+ public void sensorRotation_locked_halfFolded_configOff_rotationUnchanged() throws Exception {
+ mBuilder.setIsFoldable(true);
+ mBuilder.setSupportHalfFoldAutoRotateOverride(false);
+ mBuilder.build();
+ configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, false);
+
+ enableOrientationSensor();
+
+ mTarget.foldStateChanged(DeviceStateController.DeviceState.OPEN);
+ freezeRotation(Surface.ROTATION_270);
+
+ mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_0));
+ assertTrue(waitForUiHandler());
+ // No rotation...
+ assertEquals(Surface.ROTATION_270, mTarget.rotationForOrientation(
+ SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0));
+
+ // ... half-fold -> still no rotation
+ mTarget.foldStateChanged(DeviceStateController.DeviceState.HALF_FOLDED);
+ assertTrue(waitForUiHandler());
+ verify(sMockWm).updateRotation(false, false);
+ assertTrue(waitForUiHandler());
+ assertEquals(Surface.ROTATION_270, mTarget.rotationForOrientation(
+ SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0));
+ }
+
// =================================
// Tests for Policy based Rotation
// =================================
@@ -1017,7 +1045,7 @@
@Test
public void testSensorRotationAfterDisplayChangeBeforeTimeout_ignoresSensor() throws Exception {
- mBuilder.setSupportHalfFoldAutoRotateOverride(true)
+ mBuilder.setIsFoldable(true)
.setPauseRotationWhenUnfolding(true)
.setDisplaySwitchRotationBlockTimeMs(1000)
.build();
@@ -1035,7 +1063,7 @@
@Test
public void testSensorRotationAfterDisplayChangeAfterTimeout_usesSensor() throws Exception {
- mBuilder.setSupportHalfFoldAutoRotateOverride(true)
+ mBuilder.setIsFoldable(true)
.setPauseRotationWhenUnfolding(true)
.setDisplaySwitchRotationBlockTimeMs(1000)
.build();
@@ -1053,7 +1081,7 @@
@Test
public void testSensorRotationAfterHingeEventBeforeTimeout_ignoresSensor() throws Exception {
- mBuilder.setSupportHalfFoldAutoRotateOverride(true)
+ mBuilder.setIsFoldable(true)
.setPauseRotationWhenUnfolding(true)
.setMaxHingeAngle(165)
.setHingeAngleRotationBlockTimeMs(400)
@@ -1073,7 +1101,7 @@
@Test
public void testSensorRotationAfterHingeEventBeforeTimeoutFlagDisabled_usesSensorData()
throws Exception {
- mBuilder.setSupportHalfFoldAutoRotateOverride(true)
+ mBuilder.setIsFoldable(true)
.setPauseRotationWhenUnfolding(false)
.setMaxHingeAngle(165)
.setHingeAngleRotationBlockTimeMs(400)
@@ -1092,7 +1120,7 @@
@Test
public void testSensorRotationAfterHingeEventAfterTimeout_usesSensorData() throws Exception {
- mBuilder.setSupportHalfFoldAutoRotateOverride(true)
+ mBuilder.setIsFoldable(true)
.setPauseRotationWhenUnfolding(true)
.setMaxHingeAngle(165)
.setHingeAngleRotationBlockTimeMs(400)
@@ -1112,7 +1140,7 @@
@Test
public void testSensorRotationAfterLargeHingeEventBeforeTimeout_usesSensor() throws Exception {
- mBuilder.setSupportHalfFoldAutoRotateOverride(true)
+ mBuilder.setIsFoldable(true)
.setPauseRotationWhenUnfolding(true)
.setMaxHingeAngle(165)
.setHingeAngleRotationBlockTimeMs(400)
@@ -1254,6 +1282,7 @@
private int mCarDockRotation;
private int mDeskDockRotation;
private int mUndockedHdmiRotation;
+ private boolean mIsFoldable;
private DisplayRotationBuilder setIsDefaultDisplay(boolean isDefaultDisplay) {
mIsDefaultDisplay = isDefaultDisplay;
@@ -1308,9 +1337,17 @@
return this;
}
+ private DisplayRotationBuilder setIsFoldable(boolean value) {
+ mIsFoldable = value;
+ return this;
+ }
+
private DisplayRotationBuilder setSupportHalfFoldAutoRotateOverride(
boolean supportHalfFoldAutoRotateOverride) {
mSupportHalfFoldAutoRotateOverride = supportHalfFoldAutoRotateOverride;
+ if (supportHalfFoldAutoRotateOverride) {
+ mIsFoldable = true;
+ }
return this;
}
@@ -1455,6 +1492,11 @@
when(mMockContext.getResources().getBoolean(
com.android.internal.R.bool.config_windowManagerHalfFoldAutoRotateOverride))
.thenReturn(mSupportHalfFoldAutoRotateOverride);
+
+ when(mMockContext.getResources().getIntArray(
+ R.array.config_foldedDeviceStates))
+ .thenReturn(mIsFoldable ? new int[]{0} : new int[]{});
+
mMockDisplayRotationReversionController =
mock(DisplayRotationReversionController.class);
when(mMockDisplayContent.getRotationReversionController())
diff --git a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
index e3d1b9c..6305bb6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
@@ -47,7 +47,6 @@
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
-import android.content.res.Resources;
import android.graphics.Rect;
import android.os.IBinder;
import android.os.RemoteException;
@@ -65,9 +64,9 @@
import androidx.test.filters.SmallTest;
-import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.AdditionalMatchers;
import java.util.List;
@@ -85,14 +84,6 @@
private static final int INITIAL_HEIGHT = 900;
private static final int SECOND_WIDTH = 300;
- @Before
- public void setup() {
- Resources resources = mWm.mContext.getResources();
- spyOn(resources);
- doReturn(false).when(resources).getBoolean(
- com.android.internal.R.bool.config_offsetWallpaperToCenterOfLargestDisplay);
- }
-
@Test
public void testWallpaperScreenshot() {
WindowSurfaceController windowSurfaceController = mock(WindowSurfaceController.class);
@@ -190,16 +181,24 @@
spyOn(dc.mWallpaperController);
doReturn(true).when(dc.mWallpaperController).isWallpaperVisible();
-
+ dc.mWallpaperController.setMinWallpaperScale(.6f);
+ dc.mWallpaperController.setMaxWallpaperScale(1.2f);
dc.mWallpaperController.adjustWallpaperWindows();
+ spyOn(wallpaperWindow);
spyOn(wallpaperWindow.mClient);
float zoom = .5f;
+ float zoomScale = .9f;
+ wallpaperWindow.mShouldScaleWallpaper = true;
+
dc.mWallpaperController.setWallpaperZoomOut(homeWindow, zoom);
assertEquals(zoom, wallpaperWindow.mWallpaperZoomOut, .01f);
- verify(wallpaperWindow.mClient).dispatchWallpaperOffsets(anyFloat(), anyFloat(), anyFloat(),
- anyFloat(), eq(zoom), anyBoolean());
+ verify(wallpaperWindow.mClient)
+ .dispatchWallpaperOffsets(
+ anyFloat(), anyFloat(), anyFloat(), anyFloat(), eq(zoom), anyBoolean());
+ verify(wallpaperWindow)
+ .setWallpaperOffset(anyInt(), anyInt(), AdditionalMatchers.eq(zoomScale, .01f));
}
@Test
@@ -213,9 +212,12 @@
spyOn(dc.mWallpaperController);
doReturn(true).when(dc.mWallpaperController).isWallpaperVisible();
+ dc.mWallpaperController.setMinWallpaperScale(.6f);
+ dc.mWallpaperController.setMaxWallpaperScale(1.2f);
dc.mWallpaperController.adjustWallpaperWindows();
+ spyOn(wallpaperWindow);
spyOn(wallpaperWindow.mClient);
float newZoom = .5f;
@@ -227,6 +229,9 @@
assertEquals(1f, wallpaperWindow.mWallpaperScale, .01f);
verify(wallpaperWindow.mClient).dispatchWallpaperOffsets(anyFloat(), anyFloat(), anyFloat(),
anyFloat(), eq(newZoom), anyBoolean());
+ // As the expected scale is .9 with a zoom of .5f and min and max scale of .6 and 1.2,
+ // if it's passing a scale of 1 it's not scaling the wallpaper.
+ verify(wallpaperWindow).setWallpaperOffset(anyInt(), anyInt(), eq(1f));
}
@Test
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 040c5b0..a4ad0ce 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -1319,8 +1319,11 @@
private final Context mContext;
// Cache of Resource that has been created in getResourcesForSubId. Key is a Pair containing
- // the Context and subId.
- private static final Map<Pair<Context, Integer>, Resources> sResourcesCache =
+ // the Package Name and subId. Applications can create new contexts from
+ // {@link android.content.Context#createPackageContext} with the same resources for different
+ // purposes. Therefore, Cache can be wasted for resources from different contexts in the same
+ // package. Use the package name rather than the context itself as a key value of cache.
+ private static final Map<Pair<String, Integer>, Resources> sResourcesCache =
new ConcurrentHashMap<>();
/**
@@ -2809,12 +2812,13 @@
boolean useRootLocale) {
// Check if resources for this context and subId already exist in the resource cache.
// Resources that use the root locale are not cached.
- Pair<Context, Integer> cacheKey = null;
+ Pair<String, Integer> cacheKey = null;
if (isValidSubscriptionId(subId) && !useRootLocale) {
- cacheKey = Pair.create(context, subId);
- if (sResourcesCache.containsKey(cacheKey)) {
+ cacheKey = Pair.create(context.getPackageName(), subId);
+ Resources cached = sResourcesCache.get(cacheKey);
+ if (cached != null) {
// Cache hit. Use cached Resources.
- return sResourcesCache.get(cacheKey);
+ return cached;
}
}
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index 1b5c537..26c17a4 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -399,6 +399,11 @@
public @interface ProtocolType {}
// Possible values for MVNO type.
+ /**
+ * Default value for MVNO type if it's not set.
+ * @hide
+ */
+ public static final int MVNO_TYPE_UNKNOWN = -1;
/** MVNO type for service provider name. */
public static final int MVNO_TYPE_SPN = 0;
/** MVNO type for IMSI. */
@@ -410,10 +415,11 @@
/** @hide */
@IntDef(prefix = { "MVNO_TYPE_" }, value = {
- MVNO_TYPE_SPN,
- MVNO_TYPE_IMSI,
- MVNO_TYPE_GID,
- MVNO_TYPE_ICCID,
+ MVNO_TYPE_UNKNOWN,
+ MVNO_TYPE_SPN,
+ MVNO_TYPE_IMSI,
+ MVNO_TYPE_GID,
+ MVNO_TYPE_ICCID,
})
@Retention(RetentionPolicy.SOURCE)
public @interface MvnoType {}
@@ -1480,7 +1486,7 @@
String mvnoTypeString = TextUtils.isEmpty(mvnoType)
? mvnoType : mvnoType.toLowerCase(Locale.ROOT);
Integer mvnoTypeInt = MVNO_TYPE_STRING_MAP.get(mvnoTypeString);
- return mvnoTypeInt == null ? UNSPECIFIED_INT : mvnoTypeInt;
+ return mvnoTypeInt == null ? MVNO_TYPE_UNKNOWN : mvnoTypeInt;
}
/** @hide */
@@ -1755,7 +1761,7 @@
private int mMaxConns;
private int mWaitTime;
private int mMaxConnsTime;
- private int mMvnoType = UNSPECIFIED_INT;
+ private int mMvnoType = MVNO_TYPE_UNKNOWN;
private String mMvnoMatchData;
private int mApnSetId;
private int mCarrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
index 1a77785..4032121 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
@@ -170,9 +170,7 @@
* the SF trace
*/
fun LegacyFlickerTest.navBarLayerPositionAtStart() {
- assertLayersStart {
- assertNavBarPosition(this, scenario.isGesturalNavigation)
- }
+ assertLayersStart { assertNavBarPosition(this, scenario.isGesturalNavigation) }
}
/**
@@ -180,9 +178,7 @@
* the SF trace
*/
fun LegacyFlickerTest.navBarLayerPositionAtEnd() {
- assertLayersEnd {
- assertNavBarPosition(this, scenario.isGesturalNavigation)
- }
+ assertLayersEnd { assertNavBarPosition(this, scenario.isGesturalNavigation) }
}
private fun assertNavBarPosition(sfState: LayerTraceEntrySubject, isGesturalNavigation: Boolean) {
@@ -195,19 +191,23 @@
when (navBarPosition) {
Position.TOP ->
- navBarRegion.hasSameTopPosition(displayArea)
+ navBarRegion
+ .hasSameTopPosition(displayArea)
.hasSameLeftPosition(displayArea)
.hasSameRightPosition(displayArea)
Position.BOTTOM ->
- navBarRegion.hasSameBottomPosition(displayArea)
+ navBarRegion
+ .hasSameBottomPosition(displayArea)
.hasSameLeftPosition(displayArea)
.hasSameRightPosition(displayArea)
Position.LEFT ->
- navBarRegion.hasSameLeftPosition(displayArea)
+ navBarRegion
+ .hasSameLeftPosition(displayArea)
.hasSameTopPosition(displayArea)
.hasSameBottomPosition(displayArea)
Position.RIGHT ->
- navBarRegion.hasSameRightPosition(displayArea)
+ navBarRegion
+ .hasSameRightPosition(displayArea)
.hasSameTopPosition(displayArea)
.hasSameBottomPosition(displayArea)
else -> error("Unknown position $navBarPosition")
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/ActivityEmbeddingTestBase.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/ActivityEmbeddingTestBase.kt
index e1af6e9..6209a08 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/ActivityEmbeddingTestBase.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/ActivityEmbeddingTestBase.kt
@@ -16,9 +16,9 @@
package com.android.server.wm.flicker.activityembedding
-import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.platform.test.annotations.Presubmit
import android.tools.common.traces.component.ComponentNameMatcher
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import com.android.server.wm.flicker.BaseTest
import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
import org.junit.Before
@@ -38,8 +38,6 @@
@Test
open fun backgroundLayerNeverVisible() {
val backgroundColorLayer = ComponentNameMatcher("", "Animation Background")
- flicker.assertLayers {
- isInvisible(backgroundColorLayer)
- }
+ flicker.assertLayers { isInvisible(backgroundColorLayer) }
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/layoutchange/HorizontalSplitChangeRatioTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/layoutchange/HorizontalSplitChangeRatioTest.kt
index d418407..c3529ba 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/layoutchange/HorizontalSplitChangeRatioTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/layoutchange/HorizontalSplitChangeRatioTest.kt
@@ -23,8 +23,8 @@
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -35,9 +35,8 @@
* Test changing split ratio at runtime on a horizona split.
*
* Setup: Launch A|B in horizontal split with B being the secondary activity, by default A and B
- * windows are equal in size. B is on the top and A is on the bottom.
- * Transitions:
- * Change the split ratio to A:B=0.7:0.3, expect bounds change for both A and B.
+ * windows are equal in size. B is on the top and A is on the bottom. Transitions: Change the split
+ * ratio to A:B=0.7:0.3, expect bounds change for both A and B.
*
* To run this test: `atest FlickerTests:HorizontalSplitChangeRatioTest`
*/
@@ -46,7 +45,7 @@
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class HorizontalSplitChangeRatioTest(flicker: LegacyFlickerTest) :
- ActivityEmbeddingTestBase(flicker) {
+ ActivityEmbeddingTestBase(flicker) {
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit = {
setup {
@@ -54,12 +53,9 @@
testApp.launchViaIntent(wmHelper)
testApp.launchSecondaryActivityHorizontally(wmHelper)
startDisplayBounds =
- wmHelper.currentState.layerState.physicalDisplayBounds
- ?: error("Display not found")
+ wmHelper.currentState.layerState.physicalDisplayBounds ?: error("Display not found")
}
- transitions {
- testApp.changeSecondaryActivityRatio(wmHelper)
- }
+ transitions { testApp.changeSecondaryActivityRatio(wmHelper) }
teardown {
tapl.goHome()
testApp.exit(wmHelper)
@@ -94,7 +90,8 @@
@Test
fun secondaryActivityWindowIsAlwaysVisible() {
flicker.assertWm {
- isAppWindowVisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT) }
+ isAppWindowVisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ }
}
/** Assert the Secondary activity window is always visible. */
@@ -110,15 +107,17 @@
fun secondaryActivityAdjustsHeightRuntime() {
flicker.assertLayersStart {
val topLayerRegion =
- this.visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ this.visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
val bottomLayerRegion =
- this.visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+ this.visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
// Compare dimensions of two splits, given we're using default split attributes,
// both activities take up the same visible size on the display.
check { "height" }
- .that(topLayerRegion.region.height).isEqual(bottomLayerRegion.region.height)
+ .that(topLayerRegion.region.height)
+ .isEqual(bottomLayerRegion.region.height)
check { "width" }
- .that(topLayerRegion.region.width).isEqual(bottomLayerRegion.region.width)
+ .that(topLayerRegion.region.width)
+ .isEqual(bottomLayerRegion.region.width)
topLayerRegion.notOverlaps(bottomLayerRegion.region)
// Layers of two activities sum to be fullscreen size on display.
topLayerRegion.plus(bottomLayerRegion.region).coversExactly(startDisplayBounds)
@@ -126,20 +125,20 @@
flicker.assertLayersEnd {
val topLayerRegion =
- this.visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ this.visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
val bottomLayerRegion =
- this.visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+ this.visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
// Compare dimensions of two splits, given we're using default split attributes,
// both activities take up the same visible size on the display.
check { "height" }
- .that(topLayerRegion.region.height).isLower(bottomLayerRegion.region.height)
+ .that(topLayerRegion.region.height)
+ .isLower(bottomLayerRegion.region.height)
check { "height" }
- .that(
- topLayerRegion.region.height / 0.3f -
- bottomLayerRegion.region.height / 0.7f)
- .isLower(0.1f)
+ .that(topLayerRegion.region.height / 0.3f - bottomLayerRegion.region.height / 0.7f)
+ .isLower(0.1f)
check { "width" }
- .that(topLayerRegion.region.width).isEqual(bottomLayerRegion.region.width)
+ .that(topLayerRegion.region.width)
+ .isEqual(bottomLayerRegion.region.width)
topLayerRegion.notOverlaps(bottomLayerRegion.region)
// Layers of two activities sum to be fullscreen size on display.
topLayerRegion.plus(bottomLayerRegion.region).coversExactly(startDisplayBounds)
@@ -159,4 +158,4 @@
@JvmStatic
fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
-}
\ No newline at end of file
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/MainActivityStartsSecondaryWithAlwaysExpandTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/MainActivityStartsSecondaryWithAlwaysExpandTest.kt
index 845e649..244c5dc 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/MainActivityStartsSecondaryWithAlwaysExpandTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/MainActivityStartsSecondaryWithAlwaysExpandTest.kt
@@ -70,8 +70,7 @@
@Ignore("Not applicable to this CUJ.") override fun navBarWindowIsVisibleAtStartAndEnd() {}
- @FlakyTest(bugId = 291575593)
- override fun entireScreenCovered() {}
+ @FlakyTest(bugId = 291575593) override fun entireScreenCovered() {}
@Ignore("Not applicable to this CUJ.") override fun statusBarWindowIsAlwaysVisible() {}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenThirdActivityOverSplitTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenThirdActivityOverSplitTest.kt
index 404f329..4bb2246 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenThirdActivityOverSplitTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenThirdActivityOverSplitTest.kt
@@ -18,7 +18,6 @@
import android.platform.test.annotations.Presubmit
import android.tools.common.datatypes.Rect
-import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt
index 68b7e17..f409c4e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt
@@ -104,8 +104,10 @@
flicker.assertWm {
notContains(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
.then()
- .isAppWindowInvisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT,
- isOptional = true)
+ .isAppWindowInvisible(
+ ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT,
+ isOptional = true
+ )
.then()
.isAppWindowVisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
}
@@ -133,8 +135,10 @@
}
// Begin of transition.
.then()
- .isAppWindowInvisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT,
- isOptional = true)
+ .isAppWindowInvisible(
+ ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT,
+ isOptional = true
+ )
.then()
.invoke("mainAndSecondaryInSplit") {
val mainActivityRegion =
@@ -174,8 +178,10 @@
.coversExactly(startDisplayBounds)
}
.then()
- .isInvisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT,
- isOptional = true)
+ .isInvisible(
+ ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT,
+ isOptional = true
+ )
.then()
.isVisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt
index 0417f9d..e4c35b2 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt
@@ -35,92 +35,84 @@
/**
* Test launching a secondary Activity into Picture-In-Picture mode.
*
- * Setup: Start from a split A|B.
- * Transition: B enters PIP, observe the window shrink to the bottom right corner on screen.
+ * Setup: Start from a split A|B. Transition: B enters PIP, observe the window shrink to the bottom
+ * right corner on screen.
*
* To run this test: `atest FlickerTests:SecondaryActivityEnterPipTest`
- *
*/
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class SecondaryActivityEnterPipTest (flicker: LegacyFlickerTest) :
- ActivityEmbeddingTestBase(flicker) {
+class SecondaryActivityEnterPipTest(flicker: LegacyFlickerTest) :
+ ActivityEmbeddingTestBase(flicker) {
override val transition: FlickerBuilder.() -> Unit = {
setup {
tapl.setExpectedRotationCheckEnabled(false)
testApp.launchViaIntent(wmHelper)
testApp.launchSecondaryActivity(wmHelper)
startDisplayBounds =
- wmHelper.currentState.layerState.physicalDisplayBounds
- ?: error("Can't get display bounds")
+ wmHelper.currentState.layerState.physicalDisplayBounds
+ ?: error("Can't get display bounds")
}
- transitions {
- testApp.secondaryActivityEnterPip(wmHelper)
- }
+ transitions { testApp.secondaryActivityEnterPip(wmHelper) }
teardown {
tapl.goHome()
testApp.exit(wmHelper)
}
}
- /**
- * Main and secondary activity start from a split each taking half of the screen.
- */
+ /** Main and secondary activity start from a split each taking half of the screen. */
@Presubmit
@Test
fun layersStartFromEqualSplit() {
flicker.assertLayersStart {
- val leftLayerRegion =
- visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+ val leftLayerRegion = visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
val rightLayerRegion =
- visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
// Compare dimensions of two splits, given we're using default split attributes,
// both activities take up the same visible size on the display.
check { "height" }
- .that(leftLayerRegion.region.height).isEqual(rightLayerRegion.region.height)
+ .that(leftLayerRegion.region.height)
+ .isEqual(rightLayerRegion.region.height)
check { "width" }
- .that(leftLayerRegion.region.width).isEqual(rightLayerRegion.region.width)
+ .that(leftLayerRegion.region.width)
+ .isEqual(rightLayerRegion.region.width)
leftLayerRegion.notOverlaps(rightLayerRegion.region)
leftLayerRegion.plus(rightLayerRegion.region).coversExactly(startDisplayBounds)
}
flicker.assertLayersEnd {
visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
- .coversExactly(startDisplayBounds)
+ .coversExactly(startDisplayBounds)
}
}
- /**
- * Main Activity is visible throughout the transition and becomes fullscreen.
- */
+ /** Main Activity is visible throughout the transition and becomes fullscreen. */
@Presubmit
@Test
fun mainActivityWindowBecomesFullScreen() {
flicker.assertWm { isAppWindowVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT) }
flicker.assertWmEnd {
visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
- .coversExactly(startDisplayBounds)
+ .coversExactly(startDisplayBounds)
}
}
- /**
- * Main Activity is visible throughout the transition and becomes fullscreen.
- */
+ /** Main Activity is visible throughout the transition and becomes fullscreen. */
@Presubmit
@Test
fun mainActivityLayerBecomesFullScreen() {
flicker.assertLayers {
isVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
- .then()
- .isVisible(TRANSITION_SNAPSHOT)
- .isInvisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
- .then()
- .isVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+ .then()
+ .isVisible(TRANSITION_SNAPSHOT)
+ .isInvisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+ .then()
+ .isVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
}
flicker.assertLayersEnd {
visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
- .coversExactly(startDisplayBounds)
+ .coversExactly(startDisplayBounds)
}
}
@@ -136,18 +128,15 @@
}
flicker.assertWmEnd {
val pipWindowRegion =
- visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
- check{"height"}
- .that(pipWindowRegion.region.height)
- .isLower(startDisplayBounds.height / 2)
- check{"width"}
- .that(pipWindowRegion.region.width).isLower(startDisplayBounds.width)
+ visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ check { "height" }
+ .that(pipWindowRegion.region.height)
+ .isLower(startDisplayBounds.height / 2)
+ check { "width" }.that(pipWindowRegion.region.width).isLower(startDisplayBounds.width)
}
}
- /**
- * During the transition Secondary Activity shrinks to the bottom right corner.
- */
+ /** During the transition Secondary Activity shrinks to the bottom right corner. */
@Presubmit
@Test
fun secondaryLayerShrinks() {
@@ -162,13 +151,9 @@
}
}
flicker.assertLayersEnd {
- val pipRegion = visibleRegion(
- ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
- check { "height" }
- .that(pipRegion.region.height)
- .isLower(startDisplayBounds.height / 2)
- check { "width" }
- .that(pipRegion.region.width).isLower(startDisplayBounds.width)
+ val pipRegion = visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ check { "height" }.that(pipRegion.region.height).isLower(startDisplayBounds.height / 2)
+ check { "width" }.that(pipRegion.region.width).isLower(startDisplayBounds.width)
}
}
@@ -185,4 +170,4 @@
@JvmStatic
fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
-}
\ No newline at end of file
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
index f20e8e9..11e6bbe 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
@@ -56,9 +56,7 @@
launchSecondaryActivityFromButton(wmHelper, "launch_secondary_activity_rtl_button")
}
- /**
- * Clicks the button to launch the secondary activity in a horizontal split.
- */
+ /** Clicks the button to launch the secondary activity in a horizontal split. */
fun launchSecondaryActivityHorizontally(wmHelper: WindowManagerStateHelper) {
launchSecondaryActivityFromButton(wmHelper, "launch_secondary_activity_horizontally_button")
}
@@ -67,7 +65,7 @@
fun launchThirdActivity(wmHelper: WindowManagerStateHelper) {
val launchButton =
uiDevice.wait(
- Until.findObject(By.res(getPackage(), "launch_third_activity_button")),
+ Until.findObject(By.res(packageName, "launch_third_activity_button")),
FIND_TIMEOUT
)
require(launchButton != null) { "Can't find launch third activity button on screen." }
@@ -87,7 +85,7 @@
fun launchTrampolineActivity(wmHelper: WindowManagerStateHelper) {
val launchButton =
uiDevice.wait(
- Until.findObject(By.res(getPackage(), "launch_trampoline_button")),
+ Until.findObject(By.res(packageName, "launch_trampoline_button")),
FIND_TIMEOUT
)
require(launchButton != null) { "Can't find launch trampoline activity button on screen." }
@@ -105,53 +103,45 @@
*/
fun finishSecondaryActivity(wmHelper: WindowManagerStateHelper) {
val finishButton =
- uiDevice.wait(
- Until.findObject(By.res(getPackage(), "finish_secondary_activity_button")),
- FIND_TIMEOUT
- )
+ uiDevice.wait(
+ Until.findObject(By.res(packageName, "finish_secondary_activity_button")),
+ FIND_TIMEOUT
+ )
require(finishButton != null) { "Can't find finish secondary activity button on screen." }
finishButton.click()
wmHelper
- .StateSyncBuilder()
- .withActivityRemoved(SECONDARY_ACTIVITY_COMPONENT)
- .waitForAndVerify()
- }
+ .StateSyncBuilder()
+ .withActivityRemoved(SECONDARY_ACTIVITY_COMPONENT)
+ .waitForAndVerify()
+ }
- /**
- * Clicks the button to toggle the split ratio of secondary activity.
- */
+ /** Clicks the button to toggle the split ratio of secondary activity. */
fun changeSecondaryActivityRatio(wmHelper: WindowManagerStateHelper) {
val launchButton =
- uiDevice.wait(
- Until.findObject(
- By.res(getPackage(),
- "toggle_split_ratio_button")),
- FIND_TIMEOUT
- )
+ uiDevice.wait(
+ Until.findObject(By.res(packageName, "toggle_split_ratio_button")),
+ FIND_TIMEOUT
+ )
require(launchButton != null) {
"Can't find toggle ratio for secondary activity button on screen."
}
launchButton.click()
wmHelper
- .StateSyncBuilder()
- .withAppTransitionIdle()
- .withTransitionSnapshotGone()
- .waitForAndVerify()
+ .StateSyncBuilder()
+ .withAppTransitionIdle()
+ .withTransitionSnapshotGone()
+ .waitForAndVerify()
}
fun secondaryActivityEnterPip(wmHelper: WindowManagerStateHelper) {
val pipButton =
- uiDevice.wait(
- Until.findObject(By.res(getPackage(), "secondary_enter_pip_button")),
- FIND_TIMEOUT
- )
+ uiDevice.wait(
+ Until.findObject(By.res(packageName, "secondary_enter_pip_button")),
+ FIND_TIMEOUT
+ )
require(pipButton != null) { "Can't find enter pip button on screen." }
pipButton.click()
- wmHelper
- .StateSyncBuilder()
- .withAppTransitionIdle()
- .withPipShown()
- .waitForAndVerify()
+ wmHelper.StateSyncBuilder().withAppTransitionIdle().withPipShown().waitForAndVerify()
}
/**
@@ -161,7 +151,7 @@
fun launchAlwaysExpandActivity(wmHelper: WindowManagerStateHelper) {
val launchButton =
uiDevice.wait(
- Until.findObject(By.res(getPackage(), "launch_always_expand_activity_button")),
+ Until.findObject(By.res(packageName, "launch_always_expand_activity_button")),
FIND_TIMEOUT
)
require(launchButton != null) {
@@ -171,8 +161,11 @@
wmHelper
.StateSyncBuilder()
.withActivityState(ALWAYS_EXPAND_ACTIVITY_COMPONENT, PlatformConsts.STATE_RESUMED)
- .withActivityState(MAIN_ACTIVITY_COMPONENT, PlatformConsts.STATE_PAUSED,
- PlatformConsts.STATE_STOPPED)
+ .withActivityState(
+ MAIN_ACTIVITY_COMPONENT,
+ PlatformConsts.STATE_PAUSED,
+ PlatformConsts.STATE_STOPPED
+ )
.waitForAndVerify()
}
@@ -181,16 +174,16 @@
buttonName: String
) {
val launchButton =
- uiDevice.wait(Until.findObject(By.res(getPackage(), buttonName)), FIND_TIMEOUT)
+ uiDevice.wait(Until.findObject(By.res(packageName, buttonName)), FIND_TIMEOUT)
require(launchButton != null) {
"Can't find launch secondary activity button : " + buttonName + "on screen."
}
launchButton.click()
wmHelper
- .StateSyncBuilder()
- .withActivityState(SECONDARY_ACTIVITY_COMPONENT, PlatformConsts.STATE_RESUMED)
- .withActivityState(MAIN_ACTIVITY_COMPONENT, PlatformConsts.STATE_RESUMED)
- .waitForAndVerify()
+ .StateSyncBuilder()
+ .withActivityState(SECONDARY_ACTIVITY_COMPONENT, PlatformConsts.STATE_RESUMED)
+ .withActivityState(MAIN_ACTIVITY_COMPONENT, PlatformConsts.STATE_RESUMED)
+ .waitForAndVerify()
}
/**
@@ -200,7 +193,7 @@
fun launchPlaceholderSplit(wmHelper: WindowManagerStateHelper) {
val launchButton =
uiDevice.wait(
- Until.findObject(By.res(getPackage(), "launch_placeholder_split_button")),
+ Until.findObject(By.res(packageName, "launch_placeholder_split_button")),
FIND_TIMEOUT
)
require(launchButton != null) { "Can't find launch placeholder split button on screen." }
@@ -219,7 +212,7 @@
fun launchPlaceholderSplitRTL(wmHelper: WindowManagerStateHelper) {
val launchButton =
uiDevice.wait(
- Until.findObject(By.res(getPackage(), "launch_placeholder_split_rtl_button")),
+ Until.findObject(By.res(packageName, "launch_placeholder_split_rtl_button")),
FIND_TIMEOUT
)
require(launchButton != null) { "Can't find launch placeholder split button on screen." }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt
index 747cf37..3146139 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt
@@ -41,7 +41,7 @@
*/
fun swipeDown(): Boolean {
val gameView =
- uiDevice.wait(Until.findObject(By.res(getPackage(), GAME_APP_VIEW_RES)), WAIT_TIME_MS)
+ uiDevice.wait(Until.findObject(By.res(packageName, GAME_APP_VIEW_RES)), WAIT_TIME_MS)
require(gameView != null) { "Mock game app view not found." }
val bound = gameView.getVisibleBounds()
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
index d172252..252f7d3 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
@@ -40,7 +40,7 @@
*/
open fun openIME(wmHelper: WindowManagerStateHelper) {
val editText =
- uiDevice.wait(Until.findObject(By.res(getPackage(), "plain_text_input")), FIND_TIMEOUT)
+ uiDevice.wait(Until.findObject(By.res(packageName, "plain_text_input")), FIND_TIMEOUT)
requireNotNull(editText) {
"Text field not found, this usually happens when the device " +
@@ -67,7 +67,7 @@
open fun finishActivity(wmHelper: WindowManagerStateHelper) {
val finishButton =
uiDevice.wait(
- Until.findObject(By.res(getPackage(), "finish_activity_btn")),
+ Until.findObject(By.res(packageName, "finish_activity_btn")),
FIND_TIMEOUT
)
requireNotNull(finishButton) {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeShownOnAppStartHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeShownOnAppStartHelper.kt
index 83a41ab..1a65611 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeShownOnAppStartHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeShownOnAppStartHelper.kt
@@ -71,7 +71,7 @@
if (rotation.isRotated()) {
imePackageName
} else {
- getPackage()
+ packageName
}
open(expectedPackage)
}
@@ -79,7 +79,7 @@
fun startDialogThemedActivity(wmHelper: WindowManagerStateHelper) {
val button =
uiDevice.wait(
- Until.findObject(By.res(getPackage(), "start_dialog_themed_activity_btn")),
+ Until.findObject(By.res(packageName, "start_dialog_themed_activity_btn")),
FIND_TIMEOUT
)
@@ -132,7 +132,7 @@
fun toggleFixPortraitOrientation(wmHelper: WindowManagerStateHelper) {
val button =
uiDevice.wait(
- Until.findObject(By.res(getPackage(), "toggle_fixed_portrait_btn")),
+ Until.findObject(By.res(packageName, "toggle_fixed_portrait_btn")),
FIND_TIMEOUT
)
require(button != null) {
@@ -140,7 +140,7 @@
"was left in an unknown state (e.g. Screen turned off)"
}
button.click()
- mInstrumentation.waitForIdleSync()
+ instrumentation.waitForIdleSync()
// Ensure app relaunching transition finish and the IME has shown
waitIMEShown(wmHelper)
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt
index d83b6d3..9b539c8 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt
@@ -38,7 +38,7 @@
ActivityOptions.NonResizeablePortraitActivity.COMPONENT.toFlickerComponent()
) : StandardAppHelper(instr, launcherName, component) {
- private val gestureHelper: GestureHelper = GestureHelper(mInstrumentation)
+ private val gestureHelper: GestureHelper = GestureHelper(instrumentation)
fun clickRestart(wmHelper: WindowManagerStateHelper) {
val restartButton =
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt
index c98f1c4..9895bda 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt
@@ -37,7 +37,7 @@
fun openMail(rowIdx: Int) {
val rowSel =
- By.res(getPackage(), "mail_row_item_text").textEndsWith(String.format("%04d", rowIdx))
+ By.res(packageName, "mail_row_item_text").textEndsWith(String.format("%04d", rowIdx))
var row: UiObject2? = null
for (i in 1..1000) {
row = uiDevice.wait(Until.findObject(rowSel), SHORT_WAIT_TIME_MS)
@@ -46,7 +46,7 @@
}
require(row != null) { "" }
row.click()
- uiDevice.wait(Until.gone(By.res(getPackage(), MAIL_LIST_RES_ID)), FIND_TIMEOUT)
+ uiDevice.wait(Until.gone(By.res(packageName, MAIL_LIST_RES_ID)), FIND_TIMEOUT)
}
fun scrollDown() {
@@ -55,7 +55,7 @@
}
fun waitForMailList(): UiObject2 {
- val sel = By.res(getPackage(), MAIL_LIST_RES_ID).scrollable(true)
+ val sel = By.res(packageName, MAIL_LIST_RES_ID).scrollable(true)
val ret = uiDevice.wait(Until.findObject(sel), FIND_TIMEOUT)
requireNotNull(ret) { "Unable to find $MAIL_LIST_RES_ID object" }
return ret
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt
index 5b3d308..b2f8d47 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt
@@ -36,7 +36,7 @@
) : StandardAppHelper(instr, launcherName, component) {
fun openNewTask(device: UiDevice, wmHelper: WindowManagerStateHelper) {
val button =
- device.wait(Until.findObject(By.res(getPackage(), "launch_new_task")), FIND_TIMEOUT)
+ device.wait(Until.findObject(By.res(packageName, "launch_new_task")), FIND_TIMEOUT)
requireNotNull(button) {
"Button not found, this usually happens when the device " +
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NotificationAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NotificationAppHelper.kt
index 7665690..e60c20d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NotificationAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NotificationAppHelper.kt
@@ -35,7 +35,7 @@
) : StandardAppHelper(instr, launcherName, component) {
fun postNotification(wmHelper: WindowManagerStateHelper) {
val button =
- uiDevice.wait(Until.findObject(By.res(getPackage(), "post_notification")), FIND_TIMEOUT)
+ uiDevice.wait(Until.findObject(By.res(packageName, "post_notification")), FIND_TIMEOUT)
requireNotNull(button) {
"Post notification button not found, this usually happens when the device " +
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
index 82de646..82d2ae0 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
@@ -46,12 +46,14 @@
private val mediaController: MediaController?
get() =
- mediaSessionManager.getActiveSessions(null).firstOrNull { it.packageName == `package` }
+ mediaSessionManager.getActiveSessions(null).firstOrNull {
+ it.packageName == packageName
+ }
- private val gestureHelper: GestureHelper = GestureHelper(mInstrumentation)
+ private val gestureHelper: GestureHelper = GestureHelper(instrumentation)
open fun clickObject(resId: String) {
- val selector = By.res(`package`, resId)
+ val selector = By.res(packageName, resId)
val obj = uiDevice.findObject(selector) ?: error("Could not find `$resId` object")
obj.click()
@@ -286,7 +288,7 @@
fun checkWithCustomActionsCheckbox() =
uiDevice
- .findObject(By.res(`package`, WITH_CUSTOM_ACTIONS_BUTTON_ID))
+ .findObject(By.res(packageName, WITH_CUSTOM_ACTIONS_BUTTON_ID))
?.takeIf { it.isCheckable }
?.apply { if (!isChecked) clickObject(WITH_CUSTOM_ACTIONS_BUTTON_ID) }
?: error("'With custom actions' checkbox not found")
@@ -302,7 +304,7 @@
ReplaceWith("closePipWindow(wmHelper)")
)
open fun closePipWindow() {
- closePipWindow(WindowManagerStateHelper(mInstrumentation))
+ closePipWindow(WindowManagerStateHelper(instrumentation))
}
/** Returns the pip window bounds. */
@@ -386,8 +388,10 @@
Log.d(TAG, "window " + pipAppWindow)
if (pipAppWindow == null) return@add false
val pipRegion = pipAppWindow.frameRegion
- Log.d(TAG, "region " + pipRegion +
- " covers " + windowRect.coversMoreThan(pipRegion))
+ Log.d(
+ TAG,
+ "region " + pipRegion + " covers " + windowRect.coversMoreThan(pipRegion)
+ )
return@add windowRect.coversMoreThan(pipRegion)
}
.waitForAndVerify()
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt
index 895725c..8be5769 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt
@@ -40,7 +40,7 @@
ActivityOptions.SimpleActivity.COMPONENT.toFlickerComponent()
fun openSecondActivity(device: UiDevice, wmHelper: WindowManagerStateHelper) {
- val launchActivityButton = By.res(getPackage(), LAUNCH_SECOND_ACTIVITY)
+ val launchActivityButton = By.res(packageName, LAUNCH_SECOND_ACTIVITY)
val button = device.wait(Until.findObject(launchActivityButton), FIND_TIMEOUT)
requireNotNull(button) {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt
index 57eb172..3a784ff 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt
@@ -70,8 +70,8 @@
tapl
.goHome()
.switchToAllApps()
- .getAppIcon(testApp.launcherName)
- .launch(testApp.`package`)
+ .getAppIcon(testApp.appName)
+ .launch(testApp.packageName)
}
teardown { testApp.exit(wmHelper) }
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLauncherTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLauncherTransition.kt
index 62fb570..4fc9bcb 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLauncherTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLauncherTransition.kt
@@ -30,7 +30,7 @@
@Presubmit
@Test
open fun focusChanges() {
- flicker.assertEventLog { this.focusChanges("NexusLauncherActivity", testApp.`package`) }
+ flicker.assertEventLog { this.focusChanges("NexusLauncherActivity", testApp.packageName) }
}
/**
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenTransition.kt
index 687bc19..36e66c7 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenTransition.kt
@@ -46,7 +46,7 @@
@Presubmit
@Test
open fun focusChanges() {
- flicker.assertEventLog { this.focusChanges("", testApp.`package`) }
+ flicker.assertEventLog { this.focusChanges("", testApp.packageName) }
}
/**
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/notification/Consts.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/notification/Consts.kt
index 00e75c7..b81439e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/notification/Consts.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/notification/Consts.kt
@@ -20,4 +20,4 @@
object Consts {
val IMAGE_WALLPAPER = ComponentNameMatcher("", "com.android.systemui.wallpapers.ImageWallpaper")
-}
\ No newline at end of file
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt
index 0e33390..2aa444e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt
@@ -67,7 +67,8 @@
wmHelper.StateSyncBuilder().withFullScreenApp(testApp).waitForAndVerify()
testApp.postNotification(wmHelper)
device.pressHome()
- wmHelper.StateSyncBuilder()
+ wmHelper
+ .StateSyncBuilder()
.withHomeActivityVisible()
.withWindowSurfaceDisappeared(ComponentNameMatcher.NOTIFICATION_SHADE)
.waitForAndVerify()
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
index 1987a68..bdbf0d2 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
@@ -98,7 +98,7 @@
@Presubmit
@Test
fun focusChanges() {
- flicker.assertEventLog { this.focusChanges(testApp.`package`) }
+ flicker.assertEventLog { this.focusChanges(testApp.packageName) }
}
/**
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
index 5b127c8..6d3ae43 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
@@ -116,8 +116,8 @@
flicker.assertWm {
this.invoke("isFullScreen") {
val appWindow =
- it.windowState(testApp.`package`)
- ?: error("App window for package ${testApp.`package`} not found")
+ it.windowState(testApp.packageName)
+ ?: error("App window for package ${testApp.packageName} not found")
val flags = appWindow.windowState.attributes.flags
appWindow
.check { "isFullScreen" }
@@ -134,8 +134,8 @@
flicker.assertWm {
this.invoke("isRotationSeamless") {
val appWindow =
- it.windowState(testApp.`package`)
- ?: error("App window for package ${testApp.`package`} not found")
+ it.windowState(testApp.packageName)
+ ?: error("App window for package ${testApp.packageName} not found")
val rotationAnimation = appWindow.windowState.attributes.rotationAnimation
appWindow
.check { "isRotationSeamless" }
diff --git a/tools/aapt2/cmd/Convert.cpp b/tools/aapt2/cmd/Convert.cpp
index 7381a85..387dcfe 100644
--- a/tools/aapt2/cmd/Convert.cpp
+++ b/tools/aapt2/cmd/Convert.cpp
@@ -425,6 +425,7 @@
if (force_sparse_encoding_) {
table_flattener_options_.sparse_entries = SparseEntriesMode::Forced;
}
+ table_flattener_options_.use_compact_entries = enable_compact_entries_;
if (resources_config_path_) {
if (!ExtractResourceConfig(*resources_config_path_, &context, table_flattener_options_)) {
return 1;
diff --git a/tools/aapt2/cmd/Convert.h b/tools/aapt2/cmd/Convert.h
index 15fe11f..9452e58 100644
--- a/tools/aapt2/cmd/Convert.h
+++ b/tools/aapt2/cmd/Convert.h
@@ -46,6 +46,10 @@
"This decreases APK size at the cost of resource retrieval performance.\n"
"Applies sparse encoding to all resources regardless of minSdk.",
&force_sparse_encoding_);
+ AddOptionalSwitch(
+ "--enable-compact-entries",
+ "This decreases APK size by using compact resource entries for simple data types.",
+ &enable_compact_entries_);
AddOptionalSwitch("--keep-raw-values",
android::base::StringPrintf("Preserve raw attribute values in xml files when using the"
" '%s' output format", kOutputFormatBinary),
@@ -85,6 +89,7 @@
bool verbose_ = false;
bool enable_sparse_encoding_ = false;
bool force_sparse_encoding_ = false;
+ bool enable_compact_entries_ = false;
std::optional<std::string> resources_config_path_;
};