Merge "Update lastUnconstraintedTextSize from setTextSize" into main
diff --git a/Android.bp b/Android.bp
index 59e903e..f6bfe65 100644
--- a/Android.bp
+++ b/Android.bp
@@ -389,7 +389,6 @@
// TODO(b/120066492): remove gps_debug and protolog.conf.json when the build
// system propagates "required" properly.
"gps_debug.conf",
- "core.protolog.pb",
"framework-res",
// any install dependencies should go into framework-minus-apex-install-dependencies
// rather than here to avoid bloating incremental build time
diff --git a/Ravenwood.bp b/Ravenwood.bp
index 6237e3e..c3b22c4 100644
--- a/Ravenwood.bp
+++ b/Ravenwood.bp
@@ -30,7 +30,7 @@
name: "framework-minus-apex.ravenwood-base",
tools: ["hoststubgen"],
cmd: "$(location hoststubgen) " +
- "@$(location ravenwood/ravenwood-standard-options.txt) " +
+ "@$(location ravenwood/texts/ravenwood-standard-options.txt) " +
"--debug-log $(location hoststubgen_framework-minus-apex.log) " +
"--stats-file $(location hoststubgen_framework-minus-apex_stats.csv) " +
@@ -41,13 +41,13 @@
"--gen-input-dump-file $(location hoststubgen_dump.txt) " +
"--in-jar $(location :framework-minus-apex-for-hoststubgen) " +
- "--policy-override-file $(location ravenwood/framework-minus-apex-ravenwood-policies.txt) " +
- "--annotation-allowed-classes-file $(location ravenwood/ravenwood-annotation-allowed-classes.txt) ",
+ "--policy-override-file $(location ravenwood/texts/framework-minus-apex-ravenwood-policies.txt) " +
+ "--annotation-allowed-classes-file $(location ravenwood/texts/ravenwood-annotation-allowed-classes.txt) ",
srcs: [
":framework-minus-apex-for-hoststubgen",
- "ravenwood/framework-minus-apex-ravenwood-policies.txt",
- "ravenwood/ravenwood-standard-options.txt",
- "ravenwood/ravenwood-annotation-allowed-classes.txt",
+ "ravenwood/texts/framework-minus-apex-ravenwood-policies.txt",
+ "ravenwood/texts/ravenwood-standard-options.txt",
+ "ravenwood/texts/ravenwood-annotation-allowed-classes.txt",
],
out: [
"ravenwood.jar",
@@ -104,7 +104,7 @@
name: "services.core.ravenwood-base",
tools: ["hoststubgen"],
cmd: "$(location hoststubgen) " +
- "@$(location ravenwood/ravenwood-standard-options.txt) " +
+ "@$(location ravenwood/texts/ravenwood-standard-options.txt) " +
"--debug-log $(location hoststubgen_services.core.log) " +
"--stats-file $(location hoststubgen_services.core_stats.csv) " +
@@ -115,13 +115,13 @@
"--gen-input-dump-file $(location hoststubgen_dump.txt) " +
"--in-jar $(location :services.core-for-hoststubgen) " +
- "--policy-override-file $(location ravenwood/services.core-ravenwood-policies.txt) " +
- "--annotation-allowed-classes-file $(location ravenwood/ravenwood-annotation-allowed-classes.txt) ",
+ "--policy-override-file $(location ravenwood/texts/services.core-ravenwood-policies.txt) " +
+ "--annotation-allowed-classes-file $(location ravenwood/texts/ravenwood-annotation-allowed-classes.txt) ",
srcs: [
":services.core-for-hoststubgen",
- "ravenwood/services.core-ravenwood-policies.txt",
- "ravenwood/ravenwood-standard-options.txt",
- "ravenwood/ravenwood-annotation-allowed-classes.txt",
+ "ravenwood/texts/services.core-ravenwood-policies.txt",
+ "ravenwood/texts/ravenwood-standard-options.txt",
+ "ravenwood/texts/ravenwood-annotation-allowed-classes.txt",
],
out: [
"ravenwood.jar",
diff --git a/core/api/current.txt b/core/api/current.txt
index 1cfc025..b19c3ab 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -10147,17 +10147,17 @@
public interface ComponentCallbacks {
method public void onConfigurationChanged(@NonNull android.content.res.Configuration);
- method public void onLowMemory();
+ method @Deprecated public void onLowMemory();
}
public interface ComponentCallbacks2 extends android.content.ComponentCallbacks {
method public void onTrimMemory(int);
field public static final int TRIM_MEMORY_BACKGROUND = 40; // 0x28
- field public static final int TRIM_MEMORY_COMPLETE = 80; // 0x50
- field public static final int TRIM_MEMORY_MODERATE = 60; // 0x3c
- field public static final int TRIM_MEMORY_RUNNING_CRITICAL = 15; // 0xf
- field public static final int TRIM_MEMORY_RUNNING_LOW = 10; // 0xa
- field public static final int TRIM_MEMORY_RUNNING_MODERATE = 5; // 0x5
+ field @Deprecated public static final int TRIM_MEMORY_COMPLETE = 80; // 0x50
+ field @Deprecated public static final int TRIM_MEMORY_MODERATE = 60; // 0x3c
+ field @Deprecated public static final int TRIM_MEMORY_RUNNING_CRITICAL = 15; // 0xf
+ field @Deprecated public static final int TRIM_MEMORY_RUNNING_LOW = 10; // 0xa
+ field @Deprecated public static final int TRIM_MEMORY_RUNNING_MODERATE = 5; // 0x5
field public static final int TRIM_MEMORY_UI_HIDDEN = 20; // 0x14
}
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index ca5d3eb..6189703 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -3676,6 +3676,10 @@
field public static final int FLAG_IS_ACCESSIBILITY_EVENT = 2048; // 0x800
}
+ public final class PointerIcon implements android.os.Parcelable {
+ method @FlaggedApi("android.view.flags.enable_vector_cursors") public void setDrawNativeDropShadow(boolean);
+ }
+
@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD}) public @interface RemotableViewMethod {
method public abstract String asyncImpl() default "";
}
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 0ed25eb..7ed10e7 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -18,7 +18,7 @@
import static android.location.flags.Flags.FLAG_LOCATION_BYPASS;
-import static android.media.audio.Flags.foregroundAudioControl;
+import static android.media.audio.Flags.roForegroundAudioControl;
import static android.permission.flags.Flags.FLAG_OP_ENABLE_MOBILE_DATA_BY_USER;
import static android.view.contentprotection.flags.Flags.FLAG_CREATE_ACCESSIBILITY_OVERLAY_APP_OP_ENABLED;
import static android.view.contentprotection.flags.Flags.FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED;
@@ -3246,7 +3246,7 @@
* @hide
*/
public static @Mode int opToDefaultMode(int op) {
- if (op == OP_TAKE_AUDIO_FOCUS && foregroundAudioControl()) {
+ if (op == OP_TAKE_AUDIO_FOCUS && roForegroundAudioControl()) {
// when removing the flag, change the entry in sAppOpInfos for OP_TAKE_AUDIO_FOCUS
return AppOpsManager.MODE_FOREGROUND;
}
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index 08636ae..55ce90d 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -157,7 +157,6 @@
ParceledListSlice<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum, int flags,
int userId);
boolean isTopActivityImmersive();
- ActivityManager.TaskDescription getTaskDescription(int taskId);
void reportAssistContextExtras(in IBinder assistToken, in Bundle extras,
in AssistStructure structure, in AssistContent content, in Uri referrer);
diff --git a/core/java/android/content/ComponentCallbacks.java b/core/java/android/content/ComponentCallbacks.java
index 428545d..fb9536f 100644
--- a/core/java/android/content/ComponentCallbacks.java
+++ b/core/java/android/content/ComponentCallbacks.java
@@ -55,15 +55,11 @@
* That is, before reaching the point of killing processes hosting
* service and foreground UI that we would like to avoid killing.
*
- * <p>You should implement this method to release
- * any caches or other unnecessary resources you may be holding on to.
- * The system will perform a garbage collection for you after returning from this method.
- * <p>Preferably, you should implement {@link ComponentCallbacks2#onTrimMemory} from
- * {@link ComponentCallbacks2} to incrementally unload your resources based on various
- * levels of memory demands. That API is available for API level 14 and higher, so you should
- * only use this {@link #onLowMemory} method as a fallback for older versions, which can be
- * treated the same as {@link ComponentCallbacks2#onTrimMemory} with the {@link
- * ComponentCallbacks2#TRIM_MEMORY_COMPLETE} level.</p>
+ * @deprecated Since API level 14 this is superseded by
+ * {@link ComponentCallbacks2#onTrimMemory}.
+ * Since API level 34 this is never called.
+ * Apps targeting API level 34 and above may provide an empty implementation.
*/
+ @Deprecated
void onLowMemory();
}
diff --git a/core/java/android/content/ComponentCallbacks2.java b/core/java/android/content/ComponentCallbacks2.java
index 6576c0f..a165b18 100644
--- a/core/java/android/content/ComponentCallbacks2.java
+++ b/core/java/android/content/ComponentCallbacks2.java
@@ -105,14 +105,20 @@
* Level for {@link #onTrimMemory(int)}: the process is nearing the end
* of the background LRU list, and if more memory isn't found soon it will
* be killed.
+ *
+ * @deprecated Apps are not notified of this level since API level 34
*/
+ @Deprecated
static final int TRIM_MEMORY_COMPLETE = 80;
/**
* Level for {@link #onTrimMemory(int)}: the process is around the middle
* of the background LRU list; freeing memory can help the system keep
* other processes running later in the list for better overall performance.
+ *
+ * @deprecated Apps are not notified of this level since API level 34
*/
+ @Deprecated
static final int TRIM_MEMORY_MODERATE = 60;
/**
@@ -139,7 +145,10 @@
* will happen after this is {@link #onLowMemory()} called to report that
* nothing at all can be kept in the background, a situation that can start
* to notably impact the user.
+ *
+ * @deprecated Apps are not notified of this level since API level 34
*/
+ @Deprecated
static final int TRIM_MEMORY_RUNNING_CRITICAL = 15;
/**
@@ -147,7 +156,10 @@
* background process, but the device is running low on memory.
* Your running process should free up unneeded resources to allow that
* memory to be used elsewhere.
+ *
+ * @deprecated Apps are not notified of this level since API level 34
*/
+ @Deprecated
static final int TRIM_MEMORY_RUNNING_LOW = 10;
/**
@@ -155,17 +167,19 @@
* background process, but the device is running moderately low on memory.
* Your running process may want to release some unneeded resources for
* use elsewhere.
+ *
+ * @deprecated Apps are not notified of this level since API level 34
*/
+ @Deprecated
static final int TRIM_MEMORY_RUNNING_MODERATE = 5;
/**
* Called when the operating system has determined that it is a good
- * time for a process to trim unneeded memory from its process. This will
- * happen for example when it goes in the background and there is not enough
- * memory to keep as many background processes running as desired. You
- * should never compare to exact values of the level, since new intermediate
- * values may be added -- you will typically want to compare if the value
- * is greater or equal to a level you are interested in.
+ * time for a process to trim unneeded memory from its process.
+ *
+ * You should never compare to exact values of the level, since new
+ * intermediate values may be added -- you will typically want to compare if
+ * the value is greater or equal to a level you are interested in.
*
* <p>To retrieve the processes current trim level at any point, you can
* use {@link android.app.ActivityManager#getMyMemoryState
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 4c0da7c..f5bff9d 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -4844,6 +4844,16 @@
public static final String FEATURE_ROTARY_ENCODER_LOW_RES =
"android.hardware.rotaryencoder.lowres";
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device has
+ * support for contextual search helper.
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_CONTEXTUAL_SEARCH_HELPER =
+ "android.software.contextualsearch";
+
/** @hide */
public static final boolean APP_ENUMERATION_ENABLED_BY_DEFAULT = true;
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 8feb133..ea7db4c 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -1081,6 +1081,12 @@
* {@link java.util.concurrent.Executor} as an argument instead of
* {@link android.os.Handler}.</p>
*
+ * <p>Do note that typically callbacks are expected to be dispatched
+ * by the executor in a single thread. If the executor uses two or
+ * more threads to dispatch callbacks, then clients must ensure correct
+ * synchronization and must also be able to handle potentially different
+ * ordering of the incoming callbacks.</p>
+ *
* @param cameraId
* The unique identifier of the camera device to open
* @param executor
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 97c03ed..81bb9ac 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -290,6 +290,55 @@
}
};
+ private class ClientStateCallback extends StateCallback {
+ private final Executor mClientExecutor;
+ private final StateCallback mClientStateCallback;
+
+ private ClientStateCallback(@NonNull Executor clientExecutor,
+ @NonNull StateCallback clientStateCallback) {
+ mClientExecutor = clientExecutor;
+ mClientStateCallback = clientStateCallback;
+ }
+
+ public void onClosed(@NonNull CameraDevice camera) {
+ mClientExecutor.execute(new Runnable() {
+ @Override
+ public void run() {
+ mClientStateCallback.onClosed(camera);
+ }
+ });
+ }
+ @Override
+ public void onOpened(@NonNull CameraDevice camera) {
+ mClientExecutor.execute(new Runnable() {
+ @Override
+ public void run() {
+ mClientStateCallback.onOpened(camera);
+ }
+ });
+ }
+
+ @Override
+ public void onDisconnected(@NonNull CameraDevice camera) {
+ mClientExecutor.execute(new Runnable() {
+ @Override
+ public void run() {
+ mClientStateCallback.onDisconnected(camera);
+ }
+ });
+ }
+
+ @Override
+ public void onError(@NonNull CameraDevice camera, int error) {
+ mClientExecutor.execute(new Runnable() {
+ @Override
+ public void run() {
+ mClientStateCallback.onError(camera, error);
+ }
+ });
+ }
+ }
+
public CameraDeviceImpl(String cameraId, StateCallback callback, Executor executor,
CameraCharacteristics characteristics,
Map<String, CameraCharacteristics> physicalIdsToChars,
@@ -300,8 +349,13 @@
throw new IllegalArgumentException("Null argument given");
}
mCameraId = cameraId;
- mDeviceCallback = callback;
- mDeviceExecutor = executor;
+ if (Flags.singleThreadExecutor()) {
+ mDeviceCallback = new ClientStateCallback(executor, callback);
+ mDeviceExecutor = Executors.newSingleThreadExecutor();
+ } else {
+ mDeviceCallback = callback;
+ mDeviceExecutor = executor;
+ }
mCharacteristics = characteristics;
mPhysicalIdsToChars = physicalIdsToChars;
mAppTargetSdkVersion = appTargetSdkVersion;
diff --git a/core/java/android/hardware/face/FaceSensorConfigurations.java b/core/java/android/hardware/face/FaceSensorConfigurations.java
index 6ef692f..1247168 100644
--- a/core/java/android/hardware/face/FaceSensorConfigurations.java
+++ b/core/java/android/hardware/face/FaceSensorConfigurations.java
@@ -22,11 +22,12 @@
import android.content.Context;
import android.hardware.biometrics.face.IFace;
import android.hardware.biometrics.face.SensorProps;
+import android.os.Binder;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.util.Log;
-import android.util.Pair;
import android.util.Slog;
import androidx.annotation.NonNull;
@@ -36,7 +37,6 @@
import java.util.List;
import java.util.Map;
import java.util.Optional;
-import java.util.function.Function;
/**
* Provides the sensor props for face sensor, if available.
@@ -74,22 +74,10 @@
/**
* Process AIDL instances to extract sensor props and add it to the sensor map.
* @param aidlInstances available face AIDL instances
- * @param getIFace function that provides the daemon for the specific instance
*/
- public void addAidlConfigs(@NonNull String[] aidlInstances,
- @NonNull Function<String, IFace> getIFace) {
+ public void addAidlConfigs(@NonNull String[] aidlInstances) {
for (String aidlInstance : aidlInstances) {
- final String fqName = IFace.DESCRIPTOR + "/" + aidlInstance;
- IFace face = getIFace.apply(fqName);
- try {
- if (face != null) {
- mSensorPropsMap.put(aidlInstance, face.getSensorProps());
- } else {
- Slog.e(TAG, "Unable to get declared service: " + fqName);
- }
- } catch (RemoteException e) {
- Log.d(TAG, "Unable to get sensor properties!");
- }
+ mSensorPropsMap.put(aidlInstance, null);
}
}
@@ -131,38 +119,31 @@
}
/**
- * Return sensor props for the given instance. If instance is not available,
- * then null is returned.
+ * Checks if {@param instance} exists.
*/
@Nullable
- public Pair<String, SensorProps[]> getSensorPairForInstance(String instance) {
- if (mSensorPropsMap.containsKey(instance)) {
- return new Pair<>(instance, mSensorPropsMap.get(instance));
- }
-
- return null;
+ public boolean doesInstanceExist(String instance) {
+ return mSensorPropsMap.containsKey(instance);
}
/**
- * Return the first pair of instance and sensor props, which does not correspond to the given
- * If instance is not available, then null is returned.
+ * Return the first HAL instance, which does not correspond to the given {@param instance}.
+ * If another instance is not available, then null is returned.
*/
@Nullable
- public Pair<String, SensorProps[]> getSensorPairNotForInstance(String instance) {
+ public String getSensorNameNotForInstance(String instance) {
Optional<String> notAVirtualInstance = mSensorPropsMap.keySet().stream().filter(
(instanceName) -> !instanceName.equals(instance)).findFirst();
- return notAVirtualInstance.map(this::getSensorPairForInstance).orElseGet(
- this::getSensorPair);
+ return notAVirtualInstance.orElse(null);
}
/**
- * Returns the first pair of instance and sensor props that has been added to the map.
+ * Returns the first instance that has been added to the map.
*/
@Nullable
- public Pair<String, SensorProps[]> getSensorPair() {
+ public String getSensorInstance() {
Optional<String> optionalInstance = mSensorPropsMap.keySet().stream().findFirst();
- return optionalInstance.map(this::getSensorPairForInstance).orElse(null);
-
+ return optionalInstance.orElse(null);
}
public boolean getResetLockoutRequiresChallenge() {
@@ -179,4 +160,31 @@
dest.writeByte((byte) (mResetLockoutRequiresChallenge ? 1 : 0));
dest.writeMap(mSensorPropsMap);
}
+
+ /**
+ * Returns face sensor props for the HAL {@param instance}.
+ */
+ @Nullable
+ public SensorProps[] getSensorPropForInstance(String instance) {
+ SensorProps[] props = mSensorPropsMap.get(instance);
+
+ //Props should not be null for HIDL configs
+ if (props != null) {
+ return props;
+ }
+
+ final String fqName = IFace.DESCRIPTOR + "/" + instance;
+ IFace face = IFace.Stub.asInterface(Binder.allowBlocking(
+ ServiceManager.waitForDeclaredService(fqName)));
+ try {
+ if (face != null) {
+ props = face.getSensorProps();
+ } else {
+ Slog.e(TAG, "Unable to get declared service: " + fqName);
+ }
+ } catch (RemoteException e) {
+ Log.d(TAG, "Unable to get sensor properties!");
+ }
+ return props;
+ }
}
diff --git a/core/java/android/hardware/fingerprint/FingerprintSensorConfigurations.java b/core/java/android/hardware/fingerprint/FingerprintSensorConfigurations.java
index f214494a..43c0da9 100644
--- a/core/java/android/hardware/fingerprint/FingerprintSensorConfigurations.java
+++ b/core/java/android/hardware/fingerprint/FingerprintSensorConfigurations.java
@@ -23,18 +23,18 @@
import android.content.Context;
import android.hardware.biometrics.fingerprint.IFingerprint;
import android.hardware.biometrics.fingerprint.SensorProps;
+import android.os.Binder;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.util.Log;
-import android.util.Pair;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
-import java.util.function.Function;
/**
* Provides the sensor props for fingerprint sensor, if available.
@@ -68,23 +68,10 @@
/**
* Process AIDL instances to extract sensor props and add it to the sensor map.
* @param aidlInstances available face AIDL instances
- * @param getIFingerprint function that provides the daemon for the specific instance
*/
- public void addAidlSensors(@NonNull String[] aidlInstances,
- @NonNull Function<String, IFingerprint> getIFingerprint) {
+ public void addAidlSensors(@NonNull String[] aidlInstances) {
for (String aidlInstance : aidlInstances) {
- try {
- final String fqName = IFingerprint.DESCRIPTOR + "/" + aidlInstance;
- final IFingerprint fp = getIFingerprint.apply(fqName);
- if (fp != null) {
- SensorProps[] props = fp.getSensorProps();
- mSensorPropsMap.put(aidlInstance, props);
- } else {
- Log.d(TAG, "IFingerprint null for instance " + aidlInstance);
- }
- } catch (RemoteException e) {
- Log.d(TAG, "Unable to get sensor properties!");
- }
+ mSensorPropsMap.put(aidlInstance, null);
}
}
@@ -133,38 +120,31 @@
}
/**
- * Return sensor props for the given instance. If instance is not available,
- * then null is returned.
+ * Checks if {@param instance} exists.
*/
@Nullable
- public Pair<String, SensorProps[]> getSensorPairForInstance(String instance) {
- if (mSensorPropsMap.containsKey(instance)) {
- return new Pair<>(instance, mSensorPropsMap.get(instance));
- }
-
- return null;
+ public boolean doesInstanceExist(String instance) {
+ return mSensorPropsMap.containsKey(instance);
}
/**
- * Return the first pair of instance and sensor props, which does not correspond to the given
- * If instance is not available, then null is returned.
+ * Return the first HAL instance, which does not correspond to the given {@param instance}.
+ * If another instance is not available, then null is returned.
*/
@Nullable
- public Pair<String, SensorProps[]> getSensorPairNotForInstance(String instance) {
+ public String getSensorNameNotForInstance(String instance) {
Optional<String> notAVirtualInstance = mSensorPropsMap.keySet().stream().filter(
(instanceName) -> !instanceName.equals(instance)).findFirst();
- return notAVirtualInstance.map(this::getSensorPairForInstance).orElseGet(
- this::getSensorPair);
+ return notAVirtualInstance.orElse(null);
}
/**
- * Returns the first pair of instance and sensor props that has been added to the map.
+ * Returns the first instance that has been added to the map.
*/
@Nullable
- public Pair<String, SensorProps[]> getSensorPair() {
+ public String getSensorInstance() {
Optional<String> optionalInstance = mSensorPropsMap.keySet().stream().findFirst();
- return optionalInstance.map(this::getSensorPairForInstance).orElse(null);
-
+ return optionalInstance.orElse(null);
}
public boolean getResetLockoutRequiresHardwareAuthToken() {
@@ -181,4 +161,31 @@
dest.writeByte((byte) (mResetLockoutRequiresHardwareAuthToken ? 1 : 0));
dest.writeMap(mSensorPropsMap);
}
+
+ /**
+ * Returns fingerprint sensor props for the HAL {@param instance}.
+ */
+ @Nullable
+ public SensorProps[] getSensorPropForInstance(String instance) {
+ SensorProps[] props = mSensorPropsMap.get(instance);
+
+ //Props should not be null for HIDL configs
+ if (props != null) {
+ return props;
+ }
+
+ try {
+ final String fqName = IFingerprint.DESCRIPTOR + "/" + instance;
+ final IFingerprint fp = IFingerprint.Stub.asInterface(Binder.allowBlocking(
+ ServiceManager.waitForDeclaredService(fqName)));
+ if (fp != null) {
+ props = fp.getSensorProps();
+ } else {
+ Log.d(TAG, "IFingerprint null for instance " + instance);
+ }
+ } catch (RemoteException e) {
+ Log.d(TAG, "Unable to get sensor properties!");
+ }
+ return props;
+ }
}
diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig
index 2710df2..3e4454f 100644
--- a/core/java/android/permission/flags.aconfig
+++ b/core/java/android/permission/flags.aconfig
@@ -116,6 +116,15 @@
}
flag {
+ name: "sensitive_content_improvements"
+ namespace: "permissions"
+ description: "Improvements to sensitive content/notification features, such as the Toast UX."
+ bug: "301960090"
+ # Referenced in WM where WM starts before DeviceConfig
+ is_fixed_read_only: true
+}
+
+flag {
name: "device_aware_permissions_enabled"
is_fixed_read_only: true
namespace: "permissions"
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 363e252..d91b051 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -12451,7 +12451,7 @@
/** @hide */
public static final int PRIVATE_SPACE_AUTO_LOCK_AFTER_INACTIVITY = 1;
/** @hide */
- public static final int PRIVATE_SPACE_AUTO_LOCK_NEVER = 2;
+ public static final int PRIVATE_SPACE_AUTO_LOCK_AFTER_DEVICE_RESTART = 2;
/**
* The different auto lock options for private space.
@@ -12461,7 +12461,7 @@
@IntDef(prefix = {"PRIVATE_SPACE_AUTO_LOCK_"}, value = {
PRIVATE_SPACE_AUTO_LOCK_ON_DEVICE_LOCK,
PRIVATE_SPACE_AUTO_LOCK_AFTER_INACTIVITY,
- PRIVATE_SPACE_AUTO_LOCK_NEVER,
+ PRIVATE_SPACE_AUTO_LOCK_AFTER_DEVICE_RESTART,
})
@Retention(RetentionPolicy.SOURCE)
public @interface PrivateSpaceAutoLockOption {
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 6dcbc8e..4e521d6 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -1050,12 +1050,10 @@
overlay.endDream();
mOverlayConnection.unbind();
mOverlayConnection = null;
- finish();
} catch (RemoteException e) {
Log.e(mTag, "could not inform overlay of dream end:" + e);
}
});
- return;
}
if (mDebug) Slog.v(mTag, "finish(): mFinished=" + mFinished);
diff --git a/core/java/android/service/quickaccesswallet/QuickAccessWalletServiceInfo.java b/core/java/android/service/quickaccesswallet/QuickAccessWalletServiceInfo.java
index e6d8fd0..8a3f6ce 100644
--- a/core/java/android/service/quickaccesswallet/QuickAccessWalletServiceInfo.java
+++ b/core/java/android/service/quickaccesswallet/QuickAccessWalletServiceInfo.java
@@ -71,9 +71,11 @@
@Nullable
static QuickAccessWalletServiceInfo tryCreate(@NonNull Context context) {
- String defaultAppPackageName = getDefaultWalletApp(context);
+ String defaultAppPackageName = null;
- if (defaultAppPackageName == null) {
+ if (isWalletRoleAvailable(context)) {
+ defaultAppPackageName = getDefaultWalletApp(context);
+ } else {
ComponentName defaultPaymentApp = getDefaultPaymentApp(context);
if (defaultPaymentApp == null) {
return null;
@@ -103,14 +105,21 @@
final long token = Binder.clearCallingIdentity();
try {
RoleManager roleManager = context.getSystemService(RoleManager.class);
- if (roleManager.isRoleAvailable(RoleManager.ROLE_WALLET)) {
- List<String> roleHolders = roleManager.getRoleHolders(RoleManager.ROLE_WALLET);
- return roleHolders.isEmpty() ? null : roleHolders.get(0);
- }
+ List<String> roleHolders = roleManager.getRoleHolders(RoleManager.ROLE_WALLET);
+ return roleHolders.isEmpty() ? null : roleHolders.get(0);
} finally {
Binder.restoreCallingIdentity(token);
}
- return null;
+ }
+
+ private static boolean isWalletRoleAvailable(Context context) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ RoleManager roleManager = context.getSystemService(RoleManager.class);
+ return roleManager.isRoleAvailable(RoleManager.ROLE_WALLET);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
private static ComponentName getDefaultPaymentApp(Context context) {
diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java
index 147d562..17d1404 100644
--- a/core/java/android/view/PointerIcon.java
+++ b/core/java/android/view/PointerIcon.java
@@ -16,8 +16,10 @@
package android.view;
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.TestApi;
import android.annotation.XmlRes;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
@@ -39,6 +41,7 @@
import android.os.PointerIconType;
import android.util.Log;
import android.util.SparseArray;
+import android.view.flags.Flags;
import com.android.internal.util.XmlUtils;
@@ -637,4 +640,15 @@
default: return Integer.toString(type);
}
}
+
+ /**
+ * Sets whether drop shadow will draw in the native code.
+ *
+ * @hide
+ */
+ @TestApi
+ @FlaggedApi(Flags.FLAG_ENABLE_VECTOR_CURSORS)
+ public void setDrawNativeDropShadow(boolean drawNativeDropShadow) {
+ mDrawNativeDropShadow = drawNativeDropShadow;
+ }
}
diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java
index c70febb..34b487f 100644
--- a/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java
+++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java
@@ -37,7 +37,6 @@
import android.view.Window;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.Flags;
import android.widget.AdapterView;
import com.android.internal.R;
@@ -248,12 +247,10 @@
boolean allowEditing = isUserSetupCompleted(this);
boolean showWhenLocked = false;
- if (Flags.allowShortcutChooserOnLockscreen()) {
- final KeyguardManager keyguardManager = getSystemService(KeyguardManager.class);
- if (keyguardManager != null && keyguardManager.isKeyguardLocked()) {
- allowEditing = false;
- showWhenLocked = true;
- }
+ final KeyguardManager keyguardManager = getSystemService(KeyguardManager.class);
+ if (keyguardManager != null && keyguardManager.isKeyguardLocked()) {
+ allowEditing = false;
+ showWhenLocked = true;
}
if (allowEditing) {
final String positiveButtonText =
diff --git a/core/java/com/android/internal/os/BinderInternal.java b/core/java/com/android/internal/os/BinderInternal.java
index c14d8d8..8063be6 100644
--- a/core/java/com/android/internal/os/BinderInternal.java
+++ b/core/java/com/android/internal/os/BinderInternal.java
@@ -45,8 +45,8 @@
static ArrayList<Runnable> sGcWatchers = new ArrayList<>();
static Runnable[] sTmpWatchers = new Runnable[1];
static long sLastGcTime;
- static final BinderProxyLimitListenerDelegate sBinderProxyLimitListenerDelegate =
- new BinderProxyLimitListenerDelegate();
+ static final BinderProxyCountEventListenerDelegate sBinderProxyCountEventListenerDelegate =
+ new BinderProxyCountEventListenerDelegate();
static final class GcWatcher {
@Override
@@ -226,15 +226,24 @@
* @param low The threshold a binder count must drop below before the callback
* can be called again. (This is to avoid many repeated calls to the
* callback in a brief period of time)
+ * @param warning The threshold between {@code high} and {@code low} where if the binder count
+ * exceeds that, the warning callback would be triggered.
*/
- public static final native void nSetBinderProxyCountWatermarks(int high, int low);
+ public static final native void nSetBinderProxyCountWatermarks(int high, int low, int warning);
/**
* Interface for callback invocation when the Binder Proxy limit is reached. onLimitReached will
* be called with the uid of the app causing too many Binder Proxies
*/
- public interface BinderProxyLimitListener {
+ public interface BinderProxyCountEventListener {
public void onLimitReached(int uid);
+
+ /**
+ * Call when the number of binder proxies from the uid of the app reaches
+ * the warning threshold.
+ */
+ default void onWarningThresholdReached(int uid) {
+ }
}
/**
@@ -243,7 +252,17 @@
* @param uid The uid of the bad behaving app sending too many binders
*/
public static void binderProxyLimitCallbackFromNative(int uid) {
- sBinderProxyLimitListenerDelegate.notifyClient(uid);
+ sBinderProxyCountEventListenerDelegate.notifyLimitReached(uid);
+ }
+
+ /**
+ * Callback used by native code to trigger a callback in java code. The callback will be
+ * triggered when too many binder proxies from a uid hits the warning limit.
+ * @param uid The uid of the bad behaving app sending too many binders
+ */
+ @SuppressWarnings("unused")
+ public static void binderProxyWarningCallbackFromNative(int uid) {
+ sBinderProxyCountEventListenerDelegate.notifyWarningReached(uid);
}
/**
@@ -252,41 +271,45 @@
* @param handler must not be null, callback will be posted through the handler;
*
*/
- public static void setBinderProxyCountCallback(BinderProxyLimitListener listener,
+ public static void setBinderProxyCountCallback(BinderProxyCountEventListener listener,
@NonNull Handler handler) {
Preconditions.checkNotNull(handler,
"Must provide NonNull Handler to setBinderProxyCountCallback when setting "
- + "BinderProxyLimitListener");
- sBinderProxyLimitListenerDelegate.setListener(listener, handler);
+ + "BinderProxyCountEventListener");
+ sBinderProxyCountEventListenerDelegate.setListener(listener, handler);
}
/**
* Clear the Binder Proxy callback
*/
public static void clearBinderProxyCountCallback() {
- sBinderProxyLimitListenerDelegate.setListener(null, null);
+ sBinderProxyCountEventListenerDelegate.setListener(null, null);
}
- static private class BinderProxyLimitListenerDelegate {
- private BinderProxyLimitListener mBinderProxyLimitListener;
+ private static class BinderProxyCountEventListenerDelegate {
+ private BinderProxyCountEventListener mBinderProxyCountEventListener;
private Handler mHandler;
- void setListener(BinderProxyLimitListener listener, Handler handler) {
+ void setListener(BinderProxyCountEventListener listener, Handler handler) {
synchronized (this) {
- mBinderProxyLimitListener = listener;
+ mBinderProxyCountEventListener = listener;
mHandler = handler;
}
}
- void notifyClient(final int uid) {
+ void notifyLimitReached(final int uid) {
synchronized (this) {
- if (mBinderProxyLimitListener != null) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mBinderProxyLimitListener.onLimitReached(uid);
- }
- });
+ if (mBinderProxyCountEventListener != null) {
+ mHandler.post(() -> mBinderProxyCountEventListener.onLimitReached(uid));
+ }
+ }
+ }
+
+ void notifyWarningReached(final int uid) {
+ synchronized (this) {
+ if (mBinderProxyCountEventListener != null) {
+ mHandler.post(() ->
+ mBinderProxyCountEventListener.onWarningThresholdReached(uid));
}
}
}
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index d2d5186..2068bd7 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -88,6 +88,7 @@
jclass mClass;
jmethodID mForceGc;
jmethodID mProxyLimitCallback;
+ jmethodID mProxyWarningCallback;
} gBinderInternalOffsets;
@@ -1240,7 +1241,7 @@
gCollectedAtRefs = gNumLocalRefsCreated + gNumDeathRefsCreated;
}
-static void android_os_BinderInternal_proxyLimitcallback(int uid)
+static void android_os_BinderInternal_proxyLimitCallback(int uid)
{
JNIEnv *env = AndroidRuntime::getJNIEnv();
env->CallStaticVoidMethod(gBinderInternalOffsets.mClass,
@@ -1254,6 +1255,20 @@
}
}
+static void android_os_BinderInternal_proxyWarningCallback(int uid)
+{
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ env->CallStaticVoidMethod(gBinderInternalOffsets.mClass,
+ gBinderInternalOffsets.mProxyWarningCallback,
+ uid);
+
+ if (env->ExceptionCheck()) {
+ ScopedLocalRef<jthrowable> excep(env, env->ExceptionOccurred());
+ binder_report_exception(env, excep.get(),
+ "*** Uncaught exception in binderProxyWarningCallbackFromNative");
+ }
+}
+
static void android_os_BinderInternal_setBinderProxyCountEnabled(JNIEnv* env, jobject clazz,
jboolean enable)
{
@@ -1278,9 +1293,10 @@
}
static void android_os_BinderInternal_setBinderProxyCountWatermarks(JNIEnv* env, jobject clazz,
- jint high, jint low)
+ jint high, jint low,
+ jint warning)
{
- BpBinder::setBinderProxyCountWatermarks(high, low);
+ BpBinder::setBinderProxyCountWatermarks(high, low, warning);
}
// ----------------------------------------------------------------------------
@@ -1295,7 +1311,7 @@
{ "nSetBinderProxyCountEnabled", "(Z)V", (void*)android_os_BinderInternal_setBinderProxyCountEnabled },
{ "nGetBinderProxyPerUidCounts", "()Landroid/util/SparseIntArray;", (void*)android_os_BinderInternal_getBinderProxyPerUidCounts },
{ "nGetBinderProxyCount", "(I)I", (void*)android_os_BinderInternal_getBinderProxyCount },
- { "nSetBinderProxyCountWatermarks", "(II)V", (void*)android_os_BinderInternal_setBinderProxyCountWatermarks}
+ { "nSetBinderProxyCountWatermarks", "(III)V", (void*)android_os_BinderInternal_setBinderProxyCountWatermarks}
};
const char* const kBinderInternalPathName = "com/android/internal/os/BinderInternal";
@@ -1307,6 +1323,8 @@
gBinderInternalOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
gBinderInternalOffsets.mForceGc = GetStaticMethodIDOrDie(env, clazz, "forceBinderGc", "()V");
gBinderInternalOffsets.mProxyLimitCallback = GetStaticMethodIDOrDie(env, clazz, "binderProxyLimitCallbackFromNative", "(I)V");
+ gBinderInternalOffsets.mProxyWarningCallback =
+ GetStaticMethodIDOrDie(env, clazz, "binderProxyWarningCallbackFromNative", "(I)V");
jclass SparseIntArrayClass = FindClassOrDie(env, "android/util/SparseIntArray");
gSparseIntArrayOffsets.classObject = MakeGlobalRefOrDie(env, SparseIntArrayClass);
@@ -1315,7 +1333,8 @@
gSparseIntArrayOffsets.put = GetMethodIDOrDie(env, gSparseIntArrayOffsets.classObject, "put",
"(II)V");
- BpBinder::setLimitCallback(android_os_BinderInternal_proxyLimitcallback);
+ BpBinder::setBinderProxyCountEventCallback(android_os_BinderInternal_proxyLimitCallback,
+ android_os_BinderInternal_proxyWarningCallback);
return RegisterMethodsOrDie(
env, kBinderInternalPathName,
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index 24031cad..4808204 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -134,6 +134,8 @@
":BinderDeathRecipientHelperApp1",
":BinderDeathRecipientHelperApp2",
":com.android.cts.helpers.aosp",
+ ":BinderProxyCountingTestApp",
+ ":BinderProxyCountingTestService",
],
}
diff --git a/core/tests/coretests/AndroidTest.xml b/core/tests/coretests/AndroidTest.xml
index 05b309b..bf2a5b8 100644
--- a/core/tests/coretests/AndroidTest.xml
+++ b/core/tests/coretests/AndroidTest.xml
@@ -22,6 +22,8 @@
<option name="test-file-name" value="FrameworksCoreTests.apk" />
<option name="test-file-name" value="BinderDeathRecipientHelperApp1.apk" />
<option name="test-file-name" value="BinderDeathRecipientHelperApp2.apk" />
+ <option name="test-file-name" value="BinderProxyCountingTestApp.apk" />
+ <option name="test-file-name" value="BinderProxyCountingTestService.apk" />
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
diff --git a/core/tests/coretests/BinderProxyCountingTestApp/AndroidManifest.xml b/core/tests/coretests/BinderProxyCountingTestApp/AndroidManifest.xml
index a971730..c8407b8 100644
--- a/core/tests/coretests/BinderProxyCountingTestApp/AndroidManifest.xml
+++ b/core/tests/coretests/BinderProxyCountingTestApp/AndroidManifest.xml
@@ -16,6 +16,9 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.frameworks.coretests.binderproxycountingtestapp">
+ <queries>
+ <package android:name="com.android.frameworks.coretests.binderproxycountingtestservice" />
+ </queries>
<application>
<service android:name=".BpcTestAppCmdService"
android:exported="true"/>
diff --git a/core/tests/coretests/BinderProxyCountingTestApp/src/com/android/frameworks/coretests/binderproxycountingtestapp/BpcTestAppCmdService.java b/core/tests/coretests/BinderProxyCountingTestApp/src/com/android/frameworks/coretests/binderproxycountingtestapp/BpcTestAppCmdService.java
index 5aae1203..a7e97d3 100644
--- a/core/tests/coretests/BinderProxyCountingTestApp/src/com/android/frameworks/coretests/binderproxycountingtestapp/BpcTestAppCmdService.java
+++ b/core/tests/coretests/BinderProxyCountingTestApp/src/com/android/frameworks/coretests/binderproxycountingtestapp/BpcTestAppCmdService.java
@@ -17,14 +17,15 @@
package com.android.frameworks.coretests.binderproxycountingtestapp;
import android.app.Service;
-import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
import android.content.ServiceConnection;
+import android.database.ContentObserver;
+import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
+import android.provider.Settings;
import android.util.Log;
import com.android.frameworks.coretests.aidl.IBinderProxyCountingService;
@@ -49,24 +50,20 @@
private IBpcTestAppCmdService.Stub mBinder = new IBpcTestAppCmdService.Stub() {
- private ArrayList<BroadcastReceiver> mBrList = new ArrayList();
+ private ArrayList<ContentObserver> mCoList = new ArrayList();
private ArrayList<ITestRemoteCallback> mTrcList = new ArrayList();
+ private Handler mHandler = new Handler();
@Override
public void createSystemBinders(int count) {
int i = 0;
while (i++ < count) {
- BroadcastReceiver br = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
-
- }
- };
- IntentFilter filt = new IntentFilter(Intent.ACTION_POWER_DISCONNECTED);
- synchronized (mBrList) {
- mBrList.add(br);
+ final ContentObserver co = new ContentObserver(mHandler) {};
+ synchronized (mCoList) {
+ mCoList.add(co);
}
- registerReceiver(br, filt);
+ getContentResolver().registerContentObserver(
+ Settings.System.CONTENT_URI, false, co);
}
}
@@ -74,11 +71,11 @@
public void releaseSystemBinders(int count) {
int i = 0;
while (i++ < count) {
- BroadcastReceiver br;
- synchronized (mBrList) {
- br = mBrList.remove(0);
+ ContentObserver co;
+ synchronized (mCoList) {
+ co = mCoList.remove(0);
}
- unregisterReceiver(br);
+ getContentResolver().unregisterContentObserver(co);
}
}
@@ -117,9 +114,9 @@
@Override
public void releaseAllBinders() {
- synchronized (mBrList) {
- while (mBrList.size() > 0) {
- unregisterReceiver(mBrList.remove(0));
+ synchronized (mCoList) {
+ while (mCoList.size() > 0) {
+ getContentResolver().unregisterContentObserver(mCoList.remove(0));
}
}
synchronized (mTrcList) {
@@ -179,4 +176,4 @@
public IBinder onBind(Intent intent) {
return mBinder;
}
-}
\ No newline at end of file
+}
diff --git a/core/tests/coretests/BinderProxyCountingTestService/src/com/android/frameworks/coretests/binderproxycountingtestservice/BpcTestServiceCmdService.java b/core/tests/coretests/BinderProxyCountingTestService/src/com/android/frameworks/coretests/binderproxycountingtestservice/BpcTestServiceCmdService.java
index 6bed2a2..0f1accc 100644
--- a/core/tests/coretests/BinderProxyCountingTestService/src/com/android/frameworks/coretests/binderproxycountingtestservice/BpcTestServiceCmdService.java
+++ b/core/tests/coretests/BinderProxyCountingTestService/src/com/android/frameworks/coretests/binderproxycountingtestservice/BpcTestServiceCmdService.java
@@ -55,8 +55,8 @@
}
@Override
- public void setBinderProxyWatermarks(int high, int low) {
- BinderInternal.nSetBinderProxyCountWatermarks(high, low);
+ public void setBinderProxyWatermarks(int high, int low, int warning) {
+ BinderInternal.nSetBinderProxyCountWatermarks(high, low, warning);
}
@Override
@@ -68,12 +68,23 @@
public void setBinderProxyCountCallback(IBpcCallbackObserver observer) {
if (observer != null) {
BinderInternal.setBinderProxyCountCallback(
- new BinderInternal.BinderProxyLimitListener() {
+ new BinderInternal.BinderProxyCountEventListener() {
@Override
public void onLimitReached(int uid) {
try {
synchronized (observer) {
- observer.onCallback(uid);
+ observer.onLimitReached(uid);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, e.toString());
+ }
+ }
+
+ @Override
+ public void onWarningThresholdReached(int uid) {
+ try {
+ synchronized (observer) {
+ observer.onWarningThresholdReached(uid);
}
} catch (Exception e) {
Log.e(TAG, e.toString());
@@ -98,4 +109,4 @@
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper());
}
-}
\ No newline at end of file
+}
diff --git a/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBpcCallbackObserver.aidl b/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBpcCallbackObserver.aidl
index c4ebd56..ada7d92 100644
--- a/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBpcCallbackObserver.aidl
+++ b/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBpcCallbackObserver.aidl
@@ -17,5 +17,6 @@
package com.android.frameworks.coretests.aidl;
interface IBpcCallbackObserver {
- void onCallback(int uid);
-}
\ No newline at end of file
+ void onLimitReached(int uid);
+ void onWarningThresholdReached(int uid);
+}
diff --git a/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBpcTestServiceCmdService.aidl b/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBpcTestServiceCmdService.aidl
index abdab41..cdcda9d 100644
--- a/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBpcTestServiceCmdService.aidl
+++ b/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBpcTestServiceCmdService.aidl
@@ -20,7 +20,7 @@
interface IBpcTestServiceCmdService {
void forceGc();
int getBinderProxyCount(int uid);
- void setBinderProxyWatermarks(int high, int low);
+ void setBinderProxyWatermarks(int high, int low, int warning);
void enableBinderProxyLimit(boolean enable);
void setBinderProxyCountCallback(IBpcCallbackObserver observer);
-}
\ No newline at end of file
+}
diff --git a/core/tests/coretests/src/android/hardware/face/FaceSensorConfigurationsTest.java b/core/tests/coretests/src/android/hardware/face/FaceSensorConfigurationsTest.java
index b61104d..7d7f8ed 100644
--- a/core/tests/coretests/src/android/hardware/face/FaceSensorConfigurationsTest.java
+++ b/core/tests/coretests/src/android/hardware/face/FaceSensorConfigurationsTest.java
@@ -18,13 +18,10 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.res.Resources;
-import android.hardware.biometrics.face.IFace;
-import android.hardware.biometrics.face.SensorProps;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
@@ -37,8 +34,6 @@
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
-import java.util.function.Function;
-
@Presubmit
@SmallTest
public class FaceSensorConfigurationsTest {
@@ -48,10 +43,6 @@
private Context mContext;
@Mock
private Resources mResources;
- @Mock
- private IFace mFace;
- @Mock
- private Function<String, IFace> mGetIFace;
private final String[] mAidlInstances = new String[]{"default", "virtual"};
private String[] mHidlConfigStrings = new String[]{"0:2:15", "0:8:15"};
@@ -59,15 +50,13 @@
@Before
public void setUp() throws RemoteException {
- when(mGetIFace.apply(anyString())).thenReturn(mFace);
- when(mFace.getSensorProps()).thenReturn(new SensorProps[]{});
when(mContext.getResources()).thenReturn(mResources);
}
@Test
public void testAidlInstanceSensorProps() {
mFaceSensorConfigurations = new FaceSensorConfigurations(false);
- mFaceSensorConfigurations.addAidlConfigs(mAidlInstances, mGetIFace);
+ mFaceSensorConfigurations.addAidlConfigs(mAidlInstances);
assertThat(mFaceSensorConfigurations.hasSensorConfigurations()).isTrue();
assertThat(!mFaceSensorConfigurations.isSingleSensorConfigurationPresent()).isTrue();
diff --git a/core/tests/coretests/src/android/hardware/fingerprint/FingerprintSensorConfigurationsTest.java b/core/tests/coretests/src/android/hardware/fingerprint/FingerprintSensorConfigurationsTest.java
index f058c16..b2f8299 100644
--- a/core/tests/coretests/src/android/hardware/fingerprint/FingerprintSensorConfigurationsTest.java
+++ b/core/tests/coretests/src/android/hardware/fingerprint/FingerprintSensorConfigurationsTest.java
@@ -18,13 +18,10 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.res.Resources;
-import android.hardware.biometrics.fingerprint.IFingerprint;
-import android.hardware.biometrics.fingerprint.SensorProps;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
@@ -37,8 +34,6 @@
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
-import java.util.function.Function;
-
@Presubmit
@SmallTest
public class FingerprintSensorConfigurationsTest {
@@ -48,10 +43,6 @@
private Context mContext;
@Mock
private Resources mResources;
- @Mock
- private IFingerprint mFingerprint;
- @Mock
- private Function<String, IFingerprint> mGetIFingerprint;
private final String[] mAidlInstances = new String[]{"default", "virtual"};
private String[] mHidlConfigStrings = new String[]{"0:2:15", "0:8:15"};
@@ -59,8 +50,6 @@
@Before
public void setUp() throws RemoteException {
- when(mGetIFingerprint.apply(anyString())).thenReturn(mFingerprint);
- when(mFingerprint.getSensorProps()).thenReturn(new SensorProps[]{});
when(mContext.getResources()).thenReturn(mResources);
}
@@ -68,7 +57,7 @@
public void testAidlInstanceSensorProps() {
mFingerprintSensorConfigurations = new FingerprintSensorConfigurations(
true /* resetLockoutRequiresHardwareAuthToken */);
- mFingerprintSensorConfigurations.addAidlSensors(mAidlInstances, mGetIFingerprint);
+ mFingerprintSensorConfigurations.addAidlSensors(mAidlInstances);
assertThat(mFingerprintSensorConfigurations.hasSensorConfigurations()).isTrue();
assertThat(!mFingerprintSensorConfigurations.isSingleSensorConfigurationPresent())
diff --git a/core/tests/coretests/src/android/os/BinderProxyCountingTest.java b/core/tests/coretests/src/android/os/BinderProxyCountingTest.java
index bcd9521..84d2995 100644
--- a/core/tests/coretests/src/android/os/BinderProxyCountingTest.java
+++ b/core/tests/coretests/src/android/os/BinderProxyCountingTest.java
@@ -88,9 +88,10 @@
private static final int BIND_SERVICE_TIMEOUT_SEC = 5;
private static final int TOO_MANY_BINDERS_TIMEOUT_SEC = 2;
+ private static final int TOO_MANY_BINDERS_WITH_KILL_TIMEOUT_SEC = 30;
- // Keep in sync with sBinderProxyCountLimit in BpBinder.cpp
- private static final int BINDER_PROXY_LIMIT = 2500;
+ // Keep in sync with BINDER_PROXY_HIGH_WATERMARK in ActivityManagerService.java
+ private static final int BINDER_PROXY_LIMIT = 6000;
private static Context sContext;
private static UiDevice sUiDevice;
@@ -175,18 +176,26 @@
}
}
- private CountDownLatch createBinderLimitLatch() throws RemoteException {
- final CountDownLatch latch = new CountDownLatch(1);
+ private CountDownLatch[] createBinderLimitLatch() throws RemoteException {
+ final CountDownLatch[] latches = new CountDownLatch[] {
+ new CountDownLatch(1), new CountDownLatch(1)
+ };
sBpcTestServiceCmdService.setBinderProxyCountCallback(
new IBpcCallbackObserver.Stub() {
@Override
- public void onCallback(int uid) {
+ public void onLimitReached(int uid) {
if (uid == sTestPkgUid) {
- latch.countDown();
+ latches[0].countDown();
+ }
+ }
+ @Override
+ public void onWarningThresholdReached(int uid) {
+ if (uid == sTestPkgUid) {
+ latches[1].countDown();
}
}
});
- return latch;
+ return latches;
}
/**
@@ -227,6 +236,7 @@
@Test
public void testBinderProxyLimitBoundary() throws Exception {
final int binderProxyLimit = 2000;
+ final int binderProxyWarning = 1900;
final int rearmThreshold = 1800;
try {
sTestAppConnection = bindService(sTestAppConsumer, sTestAppIntent);
@@ -238,19 +248,33 @@
// Get the baseline of binders naturally held by the test Package
int baseBinderCount = sBpcTestServiceCmdService.getBinderProxyCount(sTestPkgUid);
- final CountDownLatch binderLimitLatch = createBinderLimitLatch();
- sBpcTestServiceCmdService.setBinderProxyWatermarks(binderProxyLimit, rearmThreshold);
+ final CountDownLatch[] binderLatches = createBinderLimitLatch();
+ sBpcTestServiceCmdService.setBinderProxyWatermarks(binderProxyLimit, rearmThreshold,
+ binderProxyWarning);
+
+ // Create Binder Proxies up to the warning;
+ sBpcTestAppCmdService.createTestBinders(binderProxyWarning - baseBinderCount);
+ if (binderLatches[1].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ fail("Received BinderProxyLimitCallback for uid " + sTestPkgUid
+ + " when proxy warning should not have been triggered");
+ }
+
+ // Create one more Binder to trigger the warning
+ sBpcTestAppCmdService.createTestBinders(1);
+ if (!binderLatches[1].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ fail("Timed out waiting for uid " + sTestPkgUid + " to trigger the warning");
+ }
// Create Binder Proxies up to the limit
- sBpcTestAppCmdService.createTestBinders(binderProxyLimit - baseBinderCount);
- if (binderLimitLatch.await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ sBpcTestAppCmdService.createTestBinders(binderProxyLimit - binderProxyWarning - 1);
+ if (binderLatches[0].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
fail("Received BinderProxyLimitCallback for uid " + sTestPkgUid
+ " when proxy limit should not have been reached");
}
// Create one more Binder to cross the limit
sBpcTestAppCmdService.createTestBinders(1);
- if (!binderLimitLatch.await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ if (!binderLatches[0].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
fail("Timed out waiting for uid " + sTestPkgUid + " to hit limit");
}
@@ -274,12 +298,20 @@
sBpcTestServiceCmdService.forceGc();
int baseBinderCount = sBpcTestServiceCmdService.getBinderProxyCount(sTestPkgUid);
for (int testLimit : testLimits) {
- final CountDownLatch binderLimitLatch = createBinderLimitLatch();
+ final CountDownLatch[] binderLatches = createBinderLimitLatch();
// Change the BinderProxyLimit
- sBpcTestServiceCmdService.setBinderProxyWatermarks(testLimit, baseBinderCount + 10);
+ sBpcTestServiceCmdService.setBinderProxyWatermarks(testLimit, baseBinderCount + 10,
+ testLimit - 10);
+
+ // Trigger the new Binder Proxy warning
+ sBpcTestAppCmdService.createTestBinders(testLimit - 9 - baseBinderCount);
+ if (!binderLatches[1].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ fail("Timed out waiting for uid " + sTestPkgUid + " to trigger the warning");
+ }
+
// Exceed the new Binder Proxy Limit
- sBpcTestAppCmdService.createTestBinders(testLimit + 1);
- if (!binderLimitLatch.await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ sBpcTestAppCmdService.createTestBinders(10);
+ if (!binderLatches[0].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
fail("Timed out waiting for uid " + sTestPkgUid + " to hit limit");
}
@@ -297,6 +329,7 @@
public void testRearmCallbackThreshold() throws Exception {
final int binderProxyLimit = 2000;
final int exceedBinderProxyLimit = binderProxyLimit + 10;
+ final int binderProxyWarning = 1900;
final int rearmThreshold = 1800;
try {
sTestAppConnection = bindService(sTestAppConsumer, sTestAppIntent);
@@ -305,11 +338,19 @@
sBpcTestServiceCmdService.enableBinderProxyLimit(true);
sBpcTestServiceCmdService.forceGc();
- final CountDownLatch firstBinderLimitLatch = createBinderLimitLatch();
- sBpcTestServiceCmdService.setBinderProxyWatermarks(binderProxyLimit, rearmThreshold);
+ int baseBinderCount = sBpcTestServiceCmdService.getBinderProxyCount(sTestPkgUid);
+ final CountDownLatch[] firstBinderLatches = createBinderLimitLatch();
+ sBpcTestServiceCmdService.setBinderProxyWatermarks(binderProxyLimit, rearmThreshold,
+ binderProxyWarning);
+ // Trigger the Binder Proxy Waring
+ sBpcTestAppCmdService.createTestBinders(binderProxyWarning - baseBinderCount + 1);
+ if (!firstBinderLatches[1].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ fail("Timed out waiting for uid " + sTestPkgUid + " to trigger warning");
+ }
+
// Exceed the Binder Proxy Limit
- sBpcTestAppCmdService.createTestBinders(exceedBinderProxyLimit);
- if (!firstBinderLimitLatch.await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ sBpcTestAppCmdService.createTestBinders(exceedBinderProxyLimit - binderProxyWarning);
+ if (!firstBinderLatches[0].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
fail("Timed out waiting for uid " + sTestPkgUid + " to hit limit");
}
@@ -321,11 +362,20 @@
sBpcTestServiceCmdService.forceGc();
currentBinderCount = sBpcTestServiceCmdService.getBinderProxyCount(sTestPkgUid);
- final CountDownLatch secondBinderLimitLatch = createBinderLimitLatch();
+ final CountDownLatch[] secondBinderLatches = createBinderLimitLatch();
+
+ // Exceed the Binder Proxy warning which should not cause a callback since there has
+ // been no rearm
+ sBpcTestAppCmdService.createTestBinders(binderProxyWarning - currentBinderCount + 1);
+ if (secondBinderLatches[1].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ fail("Received BinderProxyLimitCallback for uid " + sTestPkgUid
+ + " when the callback has not been rearmed yet");
+ }
+
// Exceed the Binder Proxy limit which should not cause a callback since there has
// been no rearm
- sBpcTestAppCmdService.createTestBinders(exceedBinderProxyLimit - currentBinderCount);
- if (secondBinderLimitLatch.await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ sBpcTestAppCmdService.createTestBinders(exceedBinderProxyLimit - binderProxyWarning);
+ if (secondBinderLatches[0].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
fail("Received BinderProxyLimitCallback for uid " + sTestPkgUid
+ " when the callback has not been rearmed yet");
}
@@ -337,10 +387,16 @@
sBpcTestServiceCmdService.forceGc();
currentBinderCount = sBpcTestServiceCmdService.getBinderProxyCount(sTestPkgUid);
+ // Trigger the Binder Proxy Waring
+ sBpcTestAppCmdService.createTestBinders(binderProxyWarning - currentBinderCount + 1);
+ if (!secondBinderLatches[1].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ fail("Timed out waiting for uid " + sTestPkgUid + " to trigger warning");
+ }
+
// Exceed the Binder Proxy limit for the last time
sBpcTestAppCmdService.createTestBinders(exceedBinderProxyLimit - currentBinderCount);
- if (!secondBinderLimitLatch.await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ if (!secondBinderLatches[0].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
fail("Timed out waiting for uid " + sTestPkgUid + " to hit limit");
}
sBpcTestAppCmdService.releaseTestBinders(currentBinderCount);
@@ -373,7 +429,7 @@
// is not unexpected
}
- if (!binderDeathLatch.await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ if (!binderDeathLatch.await(TOO_MANY_BINDERS_WITH_KILL_TIMEOUT_SEC, TimeUnit.SECONDS)) {
sBpcTestAppCmdService.releaseSystemBinders(exceedBinderProxyLimit);
fail("Timed out waiting for uid " + sTestPkgUid + " to die.");
}
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java
index 745390d..9f5ed29 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java
@@ -53,7 +53,6 @@
import android.content.pm.ServiceInfo;
import android.os.Bundle;
import android.os.Handler;
-import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.support.test.uiautomator.By;
@@ -63,7 +62,6 @@
import android.view.View;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.Flags;
import android.view.accessibility.IAccessibilityManager;
import android.widget.Button;
@@ -298,7 +296,6 @@
}
@Test
- @RequiresFlagsEnabled(Flags.FLAG_ALLOW_SHORTCUT_CHOOSER_ON_LOCKSCREEN)
public void createDialog_onLockscreen_hasExpectedContent() {
when(mKeyguardManager.isKeyguardLocked()).thenReturn(true);
launchActivity();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index ad3be3d..59c841f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -686,7 +686,11 @@
}
}
- private void dispatchOnBackCancelled(IOnBackInvokedCallback callback) {
+ private void tryDispatchOnBackCancelled(IOnBackInvokedCallback callback) {
+ if (!mOnBackStartDispatched) {
+ Log.e(TAG, "Skipping dispatching onBackCancelled. Start was never dispatched.");
+ return;
+ }
if (callback == null) {
return;
}
@@ -745,7 +749,7 @@
if (touchTracker.getTriggerBack()) {
dispatchOrAnimateOnBackInvoked(callback, touchTracker);
} else {
- dispatchOnBackCancelled(callback);
+ tryDispatchOnBackCancelled(callback);
}
}
finishBackNavigation(touchTracker.getTriggerBack());
@@ -824,7 +828,7 @@
if (mCurrentTracker.getTriggerBack()) {
dispatchOrAnimateOnBackInvoked(mActiveCallback, mCurrentTracker);
} else {
- dispatchOnBackCancelled(mActiveCallback);
+ tryDispatchOnBackCancelled(mActiveCallback);
}
}
@@ -876,7 +880,7 @@
if (mCurrentTracker.isInInitialState()) {
if (mBackGestureStarted) {
mBackGestureStarted = false;
- dispatchOnBackCancelled(mActiveCallback);
+ tryDispatchOnBackCancelled(mActiveCallback);
finishBackNavigation(false);
ProtoLog.d(WM_SHELL_BACK_PREVIEW,
"resetTouchTracker -> reset an unfinished gesture");
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt
index 3253cac..772eae7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt
@@ -65,7 +65,7 @@
private val targetEnteringRect = RectF()
private val currentEnteringRect = RectF()
- private val taskBoundsRect = Rect()
+ private val backAnimRect = Rect()
private val cornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context)
@@ -109,10 +109,10 @@
transaction.setAnimationTransaction()
// Offset start rectangle to align task bounds.
- taskBoundsRect.set(closingTarget!!.windowConfiguration.bounds)
- taskBoundsRect.offsetTo(0, 0)
+ backAnimRect.set(closingTarget!!.localBounds)
+ backAnimRect.offsetTo(0, 0)
- startClosingRect.set(taskBoundsRect)
+ startClosingRect.set(backAnimRect)
// scale closing target into the middle for rhs and to the right for lhs
targetClosingRect.set(startClosingRect)
@@ -154,7 +154,7 @@
}
private fun getYOffset(centeredRect: RectF, touchY: Float): Float {
- val screenHeight = taskBoundsRect.height()
+ val screenHeight = backAnimRect.height()
// Base the window movement in the Y axis on the touch movement in the Y axis.
val rawYDelta = touchY - initialTouchPos.y
val yDirection = (if (rawYDelta < 0) -1 else 1)
@@ -181,8 +181,8 @@
// off the animator
startClosingRect.set(currentClosingRect)
startEnteringRect.set(currentEnteringRect)
- targetEnteringRect.set(taskBoundsRect)
- targetClosingRect.set(taskBoundsRect)
+ targetEnteringRect.set(backAnimRect)
+ targetClosingRect.set(backAnimRect)
targetClosingRect.offset(currentClosingRect.left + enteringStartOffset, 0f)
val valueAnimator = ValueAnimator.ofFloat(1f, 0f).setDuration(POST_ANIMATION_DURATION)
@@ -240,13 +240,13 @@
private fun applyTransform(leash: SurfaceControl?, rect: RectF, alpha: Float) {
if (leash == null || !leash.isValid) return
- val scale = rect.width() / taskBoundsRect.width()
+ val scale = rect.width() / backAnimRect.width()
transformMatrix.reset()
transformMatrix.setScale(scale, scale)
transformMatrix.postTranslate(rect.left, rect.top)
transaction.setAlpha(leash, alpha)
.setMatrix(leash, transformMatrix, tmpFloat9)
- .setCrop(leash, taskBoundsRect)
+ .setCrop(leash, backAnimRect)
.setCornerRadius(leash, cornerRadius)
}
@@ -267,6 +267,7 @@
transaction
.setColor(scrimLayer, colorComponents)
.setAlpha(scrimLayer!!, maxScrimAlpha)
+ .setCrop(scrimLayer!!, closingTarget!!.localBounds)
.setRelativeLayer(scrimLayer!!, closingTarget!!.leash, -1)
.show(scrimLayer)
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
index ae07812..b86e39f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
@@ -93,8 +93,9 @@
@Provides
static PipScheduler providePipScheduler(Context context,
PipBoundsState pipBoundsState,
- @ShellMainThread ShellExecutor mainExecutor) {
- return new PipScheduler(context, pipBoundsState, mainExecutor);
+ @ShellMainThread ShellExecutor mainExecutor,
+ ShellTaskOrganizer shellTaskOrganizer) {
+ return new PipScheduler(context, pipBoundsState, mainExecutor, shellTaskOrganizer);
}
@WMSingleton
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt
index 7c8fcbb..99a00b8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt
@@ -20,6 +20,7 @@
import android.util.ArrayMap
import android.util.ArraySet
import android.util.SparseArray
+import android.view.Display.INVALID_DISPLAY
import androidx.core.util.forEach
import androidx.core.util.keyIterator
import androidx.core.util.valueIterator
@@ -226,6 +227,14 @@
displayData[otherDisplayId].visibleTasks.size)
}
}
+ } else if (displayId == INVALID_DISPLAY) {
+ // Task has vanished. Check which display to remove the task from.
+ displayData.forEach { displayId, data ->
+ if (data.visibleTasks.remove(taskId)) {
+ notifyVisibleTaskListeners(displayId, data.visibleTasks.size)
+ }
+ }
+ return
}
val prevCount = getVisibleTaskCount(displayId)
@@ -236,6 +245,7 @@
}
val newCount = getVisibleTaskCount(displayId)
+ // Check if count changed
if (prevCount != newCount) {
KtProtoLog.d(
WM_SHELL_DESKTOP_MODE,
@@ -244,10 +254,6 @@
visible,
displayId
)
- }
-
- // Check if count changed
- if (prevCount != newCount) {
KtProtoLog.d(
WM_SHELL_DESKTOP_MODE,
"DesktopTaskRepo: visibleTaskCount has changed from %d to %d",
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
index 4c69cc3..1e18b8c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
@@ -245,9 +245,9 @@
Rect destinationBounds, SurfaceControl overlay, Rect appBounds) {
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
"onSwipePipToHomeAnimationStart: %s", componentName);
- mPipScheduler.setInSwipePipToHomeTransition(true);
+ mPipScheduler.onSwipePipToHomeAnimationStart(taskId, componentName, destinationBounds,
+ overlay, appBounds);
mPipRecentsAnimationListener.onPipAnimationStarted();
- // TODO: cache the overlay if provided for reparenting later.
}
//
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
index 6665013..b4ca7df 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
@@ -21,6 +21,7 @@
import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -30,9 +31,11 @@
import android.window.WindowContainerTransaction;
import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
+import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.pip.PipBoundsState;
import com.android.wm.shell.common.pip.PipUtils;
@@ -52,6 +55,7 @@
private final Context mContext;
private final PipBoundsState mPipBoundsState;
private final ShellExecutor mMainExecutor;
+ private final ShellTaskOrganizer mShellTaskOrganizer;
private PipSchedulerReceiver mSchedulerReceiver;
private PipTransitionController mPipTransitionController;
@@ -66,6 +70,16 @@
// true if Launcher has started swipe PiP to home animation
private boolean mInSwipePipToHomeTransition;
+ // Overlay leash potentially used during swipe PiP to home transition;
+ // if null while mInSwipePipToHomeTransition is true, then srcRectHint was invalid.
+ @Nullable
+ SurfaceControl mSwipePipToHomeOverlay;
+
+ // App bounds used when as a starting point to swipe PiP to home animation in Launcher;
+ // these are also used to calculate the app icon overlay buffer size.
+ @NonNull
+ final Rect mSwipePipToHomeAppBounds = new Rect();
+
/**
* Temporary PiP CUJ codes to schedule PiP related transitions directly from Shell.
* This is used for a broadcast receiver to resolve intents. This should be removed once
@@ -101,11 +115,14 @@
}
}
- public PipScheduler(Context context, PipBoundsState pipBoundsState,
- ShellExecutor mainExecutor) {
+ public PipScheduler(Context context,
+ PipBoundsState pipBoundsState,
+ ShellExecutor mainExecutor,
+ ShellTaskOrganizer shellTaskOrganizer) {
mContext = context;
mPipBoundsState = pipBoundsState;
mMainExecutor = mainExecutor;
+ mShellTaskOrganizer = shellTaskOrganizer;
if (PipUtils.isPip2ExperimentEnabled()) {
// temporary broadcast receiver to initiate exit PiP via expand
@@ -115,6 +132,10 @@
}
}
+ ShellExecutor getMainExecutor() {
+ return mMainExecutor;
+ }
+
void setPipTransitionController(PipTransitionController pipTransitionController) {
mPipTransitionController = pipTransitionController;
}
@@ -171,6 +192,24 @@
mPipTransitionController.startResizeTransition(wct, onFinishResizeCallback);
}
+ void onSwipePipToHomeAnimationStart(int taskId, ComponentName componentName,
+ Rect destinationBounds, SurfaceControl overlay, Rect appBounds) {
+ mInSwipePipToHomeTransition = true;
+ mSwipePipToHomeOverlay = overlay;
+ mSwipePipToHomeAppBounds.set(appBounds);
+ if (overlay != null) {
+ // Shell transitions might use a root animation leash, which will be removed when
+ // the Recents transition is finished. Launcher attaches the overlay leash to this
+ // animation target leash; thus, we need to reparent it to the actual Task surface now.
+ // PipTransition is responsible to fade it out and cleanup when finishing the enter PIP
+ // transition.
+ SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
+ mShellTaskOrganizer.reparentChildSurfaceToTask(taskId, overlay, tx);
+ tx.setLayer(overlay, Integer.MAX_VALUE);
+ tx.apply();
+ }
+ }
+
void setInSwipePipToHomeTransition(boolean inSwipePipToHome) {
mInSwipePipToHomeTransition = inSwipePipToHome;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
index d15da4a..b179b5b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
@@ -24,6 +24,9 @@
import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP;
import static com.android.wm.shell.transition.Transitions.TRANSIT_RESIZE_PIP;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.PictureInPictureParams;
@@ -44,6 +47,7 @@
import com.android.wm.shell.common.pip.PipBoundsState;
import com.android.wm.shell.common.pip.PipMenuController;
import com.android.wm.shell.common.pip.PipUtils;
+import com.android.wm.shell.pip.PipContentOverlay;
import com.android.wm.shell.pip.PipTransitionController;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.Transitions;
@@ -55,6 +59,11 @@
*/
public class PipTransition extends PipTransitionController {
private static final String TAG = PipTransition.class.getSimpleName();
+ /**
+ * The fixed start delay in ms when fading out the content overlay from bounds animation.
+ * The fadeout animation is guaranteed to start after the client has drawn under the new config.
+ */
+ private static final int CONTENT_OVERLAY_FADE_OUT_DELAY_MS = 400;
private final Context mContext;
private final PipScheduler mPipScheduler;
@@ -230,10 +239,13 @@
PictureInPictureParams params = pipChange.getTaskInfo().pictureInPictureParams;
Rect srcRectHint = params.getSourceRectHint();
+ Rect startBounds = pipChange.getStartAbsBounds();
Rect destinationBounds = pipChange.getEndAbsBounds();
+ WindowContainerTransaction finishWct = new WindowContainerTransaction();
+
if (PipBoundsAlgorithm.isSourceRectHintValidForEnterPip(srcRectHint, destinationBounds)) {
- float scale = (float) destinationBounds.width() / srcRectHint.width();
+ final float scale = (float) destinationBounds.width() / srcRectHint.width();
startTransaction.setWindowCrop(pipLeash, srcRectHint);
startTransaction.setPosition(pipLeash,
destinationBounds.left - srcRectHint.left * scale,
@@ -244,13 +256,62 @@
// in multi-activity case, reparenting yields new reset scales coming from pinned task.
startTransaction.setScale(pipLeash, scale, scale);
} else {
- // TODO(b/325481148): handle the case with invalid srcRectHint (using overlay).
+ final float scaleX = (float) destinationBounds.width() / startBounds.width();
+ final float scaleY = (float) destinationBounds.height() / startBounds.height();
+ final int overlaySize = PipContentOverlay.PipAppIconOverlay
+ .getOverlaySize(mPipScheduler.mSwipePipToHomeAppBounds, destinationBounds);
+ SurfaceControl overlayLeash = mPipScheduler.mSwipePipToHomeOverlay;
+
+ startTransaction.setPosition(pipLeash, destinationBounds.left, destinationBounds.top)
+ .setScale(pipLeash, scaleX, scaleY)
+ .setWindowCrop(pipLeash, startBounds)
+ .reparent(overlayLeash, pipLeash)
+ .setLayer(overlayLeash, Integer.MAX_VALUE);
+
+ if (mPipTaskToken != null) {
+ SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
+ tx.addTransactionCommittedListener(mPipScheduler.getMainExecutor(),
+ this::onClientDrawAtTransitionEnd)
+ .setScale(overlayLeash, 1f, 1f)
+ .setPosition(overlayLeash,
+ (destinationBounds.width() - overlaySize) / 2f,
+ (destinationBounds.height() - overlaySize) / 2f);
+ finishWct.setBoundsChangeTransaction(mPipTaskToken, tx);
+ }
}
startTransaction.apply();
- finishCallback.onTransitionFinished(null);
+
+ // Note that finishWct should be free of any actual WM state changes; we are using
+ // it for syncing with the client draw after delayed configuration changes are dispatched.
+ finishCallback.onTransitionFinished(finishWct.isEmpty() ? null : finishWct);
return true;
}
+ private void onClientDrawAtTransitionEnd() {
+ startOverlayFadeoutAnimation();
+ }
+
+ private void startOverlayFadeoutAnimation() {
+ ValueAnimator animator = ValueAnimator.ofFloat(1f, 0f);
+ animator.setDuration(CONTENT_OVERLAY_FADE_OUT_DELAY_MS);
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
+ tx.remove(mPipScheduler.mSwipePipToHomeOverlay);
+ tx.apply();
+ mPipScheduler.mSwipePipToHomeOverlay = null;
+ }
+ });
+ animator.addUpdateListener(animation -> {
+ float alpha = (float) animation.getAnimatedValue();
+ SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
+ tx.setAlpha(mPipScheduler.mSwipePipToHomeOverlay, alpha).apply();
+ });
+ animator.start();
+ }
+
private boolean startBoundsTypeEnterAnimation(@NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction startTransaction,
@NonNull SurfaceControl.Transaction finishTransaction,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
index 2919782..d839eae 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
@@ -557,6 +557,23 @@
}
@Test
+ public void skipsCancelWithoutStart() throws RemoteException {
+ final int type = BackNavigationInfo.TYPE_CALLBACK;
+ final ResultListener result = new ResultListener();
+ createNavigationInfo(new BackNavigationInfo.Builder()
+ .setType(type)
+ .setOnBackInvokedCallback(mAppCallback)
+ .setOnBackNavigationDone(new RemoteCallback(result)));
+ doMotionEvent(MotionEvent.ACTION_CANCEL, 0);
+ mShellExecutor.flushAll();
+
+ verify(mAppCallback, never()).onBackStarted(any());
+ verify(mAppCallback, never()).onBackProgressed(any());
+ verify(mAppCallback, never()).onBackInvoked();
+ verify(mAppCallback, never()).onBackCancelled();
+ }
+
+ @Test
public void testBackToActivity() throws RemoteException {
final CrossActivityBackAnimation animation = new CrossActivityBackAnimation(
mContext, mAnimationBackground, mRootTaskDisplayAreaOrganizer);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt
index 445f74a..9f3a4d9 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt
@@ -18,6 +18,7 @@
import android.testing.AndroidTestingRunner
import android.view.Display.DEFAULT_DISPLAY
+import android.view.Display.INVALID_DISPLAY
import androidx.test.filters.SmallTest
import com.android.wm.shell.ShellTestCase
import com.android.wm.shell.TestShellExecutor
@@ -237,6 +238,27 @@
assertThat(listener.visibleChangesOnDefaultDisplay).isEqualTo(4)
}
+ /**
+ * When a task vanishes, the displayId of the task is set to INVALID_DISPLAY.
+ * This tests that task is removed from the last parent display when it vanishes.
+ */
+ @Test
+ fun updateVisibleFreeformTasks_removeVisibleTasksRemovesTaskWithInvalidDisplay() {
+ val listener = TestVisibilityListener()
+ val executor = TestShellExecutor()
+ repo.addVisibleTasksListener(listener, executor)
+ repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 1, visible = true)
+ repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 2, visible = true)
+ executor.flushAll()
+
+ assertThat(listener.visibleTasksCountOnDefaultDisplay).isEqualTo(2)
+ repo.updateVisibleFreeformTasks(INVALID_DISPLAY, taskId = 1, visible = false)
+ executor.flushAll()
+
+ assertThat(listener.visibleChangesOnDefaultDisplay).isEqualTo(3)
+ assertThat(listener.visibleTasksCountOnDefaultDisplay).isEqualTo(1)
+ }
+
@Test
fun getVisibleTaskCount() {
// No tasks, count is 0
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsColors.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsColors.kt
index d72ec26..69aba71 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsColors.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsColors.kt
@@ -33,10 +33,6 @@
val secondaryText: Color = Color.Unspecified,
val primaryContainer: Color = Color.Unspecified,
val onPrimaryContainer: Color = Color.Unspecified,
- val spinnerHeaderContainer: Color = Color.Unspecified,
- val onSpinnerHeaderContainer: Color = Color.Unspecified,
- val spinnerItemContainer: Color = Color.Unspecified,
- val onSpinnerItemContainer: Color = Color.Unspecified,
)
internal val LocalColorScheme = staticCompositionLocalOf { SettingsColorScheme() }
@@ -76,10 +72,6 @@
secondaryText = tonalPalette.neutralVariant30,
primaryContainer = tonalPalette.primary90,
onPrimaryContainer = tonalPalette.neutral10,
- spinnerHeaderContainer = tonalPalette.primary90,
- onSpinnerHeaderContainer = tonalPalette.neutral10,
- spinnerItemContainer = tonalPalette.secondary90,
- onSpinnerItemContainer = tonalPalette.neutralVariant30,
)
}
@@ -103,10 +95,6 @@
secondaryText = tonalPalette.neutralVariant80,
primaryContainer = tonalPalette.secondary90,
onPrimaryContainer = tonalPalette.neutral10,
- spinnerHeaderContainer = tonalPalette.primary90,
- onSpinnerHeaderContainer = tonalPalette.neutral10,
- spinnerItemContainer = tonalPalette.secondary90,
- onSpinnerItemContainer = tonalPalette.neutralVariant30,
)
}
@@ -121,10 +109,6 @@
secondaryText = tonalPalette.neutralVariant80,
primaryContainer = tonalPalette.secondary90,
onPrimaryContainer = tonalPalette.neutral10,
- spinnerHeaderContainer = tonalPalette.primary90,
- onSpinnerHeaderContainer = tonalPalette.neutral10,
- spinnerItemContainer = tonalPalette.secondary90,
- onSpinnerItemContainer = tonalPalette.neutralVariant30,
)
}
@@ -139,9 +123,5 @@
secondaryText = tonalPalette.neutralVariant30,
primaryContainer = tonalPalette.primary90,
onPrimaryContainer = tonalPalette.neutral10,
- spinnerHeaderContainer = tonalPalette.primary90,
- onSpinnerHeaderContainer = tonalPalette.neutral10,
- spinnerItemContainer = tonalPalette.secondary90,
- onSpinnerItemContainer = tonalPalette.neutralVariant30,
)
}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt
index 514ad669..c48a147 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt
@@ -33,6 +33,7 @@
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
@@ -74,8 +75,8 @@
modifier = Modifier.semantics { role = Role.DropdownList },
onClick = { expanded = true },
colors = ButtonDefaults.buttonColors(
- containerColor = SettingsTheme.colorScheme.spinnerHeaderContainer,
- contentColor = SettingsTheme.colorScheme.onSpinnerHeaderContainer,
+ containerColor = MaterialTheme.colorScheme.primaryContainer,
+ contentColor = MaterialTheme.colorScheme.onPrimaryContainer,
),
contentPadding = contentPadding,
) {
@@ -85,7 +86,7 @@
DropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false },
- modifier = Modifier.background(SettingsTheme.colorScheme.spinnerItemContainer),
+ modifier = Modifier.background(MaterialTheme.colorScheme.secondaryContainer),
) {
for (option in options) {
DropdownMenuItem(
@@ -93,7 +94,7 @@
SpinnerText(
option = option,
modifier = Modifier.padding(end = 24.dp),
- color = SettingsTheme.colorScheme.onSpinnerItemContainer,
+ color = MaterialTheme.colorScheme.onSecondaryContainer,
)
},
onClick = {
@@ -138,7 +139,7 @@
@Composable
private fun SpinnerPreview() {
SettingsTheme {
- var selectedId by rememberSaveable { mutableStateOf(1) }
+ var selectedId by rememberSaveable { mutableIntStateOf(1) }
Spinner(
options = (1..3).map { SpinnerOption(id = it, text = "Option $it") },
selectedId = selectedId,
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/theme/SettingsColorsTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/theme/SettingsColorsTest.kt
index 5ea92ab..625663d 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/theme/SettingsColorsTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/theme/SettingsColorsTest.kt
@@ -37,15 +37,11 @@
assertThat(ls.categoryTitle).isNotEqualTo(ls.background)
assertThat(ls.secondaryText).isNotEqualTo(ls.background)
assertThat(ls.primaryContainer).isNotEqualTo(ls.onPrimaryContainer)
- assertThat(ls.spinnerHeaderContainer).isNotEqualTo(ls.onSpinnerHeaderContainer)
- assertThat(ls.spinnerItemContainer).isNotEqualTo(ls.onSpinnerItemContainer)
val ds = dynamicDarkColorScheme(context)
assertThat(ds.categoryTitle).isNotEqualTo(ds.background)
assertThat(ds.secondaryText).isNotEqualTo(ds.background)
assertThat(ds.primaryContainer).isNotEqualTo(ds.onPrimaryContainer)
- assertThat(ds.spinnerHeaderContainer).isNotEqualTo(ds.onSpinnerHeaderContainer)
- assertThat(ds.spinnerItemContainer).isNotEqualTo(ds.onSpinnerItemContainer)
}
@Test
@@ -58,10 +54,6 @@
assertThat(ls.secondaryText).isEqualTo(Color(red = 73, green = 69, blue = 79))
assertThat(ls.primaryContainer).isEqualTo(Color(red = 234, green = 221, blue = 255))
assertThat(ls.onPrimaryContainer).isEqualTo(Color(red = 28, green = 27, blue = 31))
- assertThat(ls.spinnerHeaderContainer).isEqualTo(Color(red = 234, green = 221, blue = 255))
- assertThat(ls.onSpinnerHeaderContainer).isEqualTo(Color(red = 28, green = 27, blue = 31))
- assertThat(ls.spinnerItemContainer).isEqualTo(Color(red = 232, green = 222, blue = 248))
- assertThat(ls.onSpinnerItemContainer).isEqualTo(Color(red = 73, green = 69, blue = 79))
val ds = darkColorScheme()
assertThat(ds.background).isEqualTo(Color(red = 28, green = 27, blue = 31))
@@ -71,9 +63,5 @@
assertThat(ds.secondaryText).isEqualTo(Color(red = 202, green = 196, blue = 208))
assertThat(ds.primaryContainer).isEqualTo(Color(red = 232, green = 222, blue = 248))
assertThat(ds.onPrimaryContainer).isEqualTo(Color(red = 28, green = 27, blue = 31))
- assertThat(ds.spinnerHeaderContainer).isEqualTo(Color(red = 234, green = 221, blue = 255))
- assertThat(ds.onSpinnerHeaderContainer).isEqualTo(Color(red = 28, green = 27, blue = 31))
- assertThat(ds.spinnerItemContainer).isEqualTo(Color(red = 232, green = 222, blue = 248))
- assertThat(ds.onSpinnerItemContainer).isEqualTo(Color(red = 73, green = 69, blue = 79))
}
}
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 69e4bd7..46c6494 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -222,6 +222,30 @@
<!-- Connected device settings. Message when the left-side and right-side hearing aids device are active. [CHAR LIMIT=NONE] -->
<string name="bluetooth_hearing_aid_left_and_right_active">Active, left and right</string>
+ <!-- Connected devices settings. Message when Bluetooth is connected and active for media only, showing remote device status and battery level. [CHAR LIMIT=NONE] -->
+ <string name="bluetooth_active_media_only_battery_level">Active (media only), <xliff:g id="battery_level_as_percentage">%1$s</xliff:g> battery</string>
+ <!-- Connected devices settings. Message when Bluetooth is connected and active for media only, showing remote device status and battery level for untethered headset. [CHAR LIMIT=NONE] -->
+ <string name="bluetooth_active_media_only_battery_level_untethered">Active (media only), L: <xliff:g id="battery_level_as_percentage" example="25%">%1$s</xliff:g> battery, R: <xliff:g id="battery_level_as_percentage" example="25%">%2$s</xliff:g> battery</string>
+ <!-- Connected devices settings. Message when Bluetooth is connected but not in use, showing remote device battery level, supports audio sharing. [CHAR LIMIT=NONE] -->
+ <string name="bluetooth_battery_level_lea_support">Connected (supports audio sharing), <xliff:g id="battery_level_as_percentage">%1$s</xliff:g> battery</string>
+ <!-- Connected devices settings. Message when Bluetooth is connected but not in use, showing remote device battery level for untethered headset, supports audio sharing. [CHAR LIMIT=NONE] -->
+ <string name="bluetooth_battery_level_untethered_lea_support">Connected (supports audio sharing), L: <xliff:g id="battery_level_as_percentage" example="25%">%1$s</xliff:g> battery, R: <xliff:g id="battery_level_as_percentage" example="25%">%2$s</xliff:g> battery</string>
+ <!-- Connected devices settings. Message when Bluetooth is connected but not in use, showing remote device battery level for the left part of the untethered headset, supports audio sharing. [CHAR LIMIT=NONE] -->
+ <string name="bluetooth_battery_level_untethered_left_lea_support">Connected (supports audio sharing), left <xliff:g id="battery_level_as_percentage" example="25%">%1$s</xliff:g></string>
+ <!-- Connected devices settings. Message when Bluetooth is connected but not in use, showing remote device battery level for the right part of the untethered headset, supports audio sharing. [CHAR LIMIT=NONE] -->
+ <string name="bluetooth_battery_level_untethered_right_lea_support">Connected (supports audio sharing), right <xliff:g id="battery_level_as_percentage" example="25%">%1$s</xliff:g></string>
+ <!-- Connected devices settings. Message when Bluetooth is connected and active for media only but no battery information, showing remote device status. [CHAR LIMIT=NONE] -->
+ <string name="bluetooth_active_media_only_no_battery_level">Active (media only)</string>
+ <!-- Connected devices settings. Message shown when bluetooth device is disconnected but is a known, previously connected device, supports audio sharing [CHAR LIMIT=NONE] -->
+ <string name="bluetooth_saved_device_lea_support">Supports audio sharing</string>
+
+ <!-- Connected device settings. Message when the left-side hearing aid device is active for media only. [CHAR LIMIT=NONE] -->
+ <string name="bluetooth_hearing_aid_media_only_left_active">Active (media only), left only</string>
+ <!-- Connected device settings. Message when the right-side hearing aid device is active for media only. [CHAR LIMIT=NONE] -->
+ <string name="bluetooth_hearing_aid_media_only_right_active">Active (media only), right only</string>
+ <!-- Connected device settings. Message when the left-side and right-side hearing aids device are active for media only. [CHAR LIMIT=NONE] -->
+ <string name="bluetooth_hearing_aid_media_only_left_and_right_active">Active (media only), left and right</string>
+
<!-- Bluetooth settings. The user-visible string that is used whenever referring to the A2DP profile. -->
<string name="bluetooth_profile_a2dp">Media audio</string>
<!-- Bluetooth settings. The user-visible string that is used whenever referring to the headset or handsfree profile. -->
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt
index 1178cc8..4bef9ef 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt
@@ -16,7 +16,6 @@
package com.android.systemui.keyguard.ui.composable
-import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.collectAsState
@@ -24,9 +23,7 @@
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalView
-import com.android.compose.animation.scene.SceneKey
-import com.android.compose.animation.scene.SceneTransitionLayout
-import com.android.compose.animation.scene.transitions
+import com.android.compose.animation.scene.SceneScope
import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
import com.android.systemui.keyguard.ui.composable.blueprint.ComposableLockscreenSceneBlueprint
import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel
@@ -45,16 +42,12 @@
private val blueprints: Set<@JvmSuppressWildcards ComposableLockscreenSceneBlueprint>,
private val clockInteractor: KeyguardClockInteractor,
) {
-
- private val sceneKeyByBlueprint: Map<ComposableLockscreenSceneBlueprint, SceneKey> by lazy {
- blueprints.associateWith { blueprint -> SceneKey(blueprint.id) }
- }
- private val sceneKeyByBlueprintId: Map<String, SceneKey> by lazy {
- sceneKeyByBlueprint.entries.associate { (blueprint, sceneKey) -> blueprint.id to sceneKey }
+ private val blueprintByBlueprintId: Map<String, ComposableLockscreenSceneBlueprint> by lazy {
+ blueprints.associateBy { it.id }
}
@Composable
- fun Content(
+ fun SceneScope.Content(
modifier: Modifier = Modifier,
) {
val coroutineScope = rememberCoroutineScope()
@@ -66,19 +59,7 @@
onDispose { clockInteractor.clockEventController.unregisterListeners() }
}
- // Switch smoothly between blueprints, any composable tagged with element() will be
- // transition-animated between any two blueprints, if they both display the same element.
- SceneTransitionLayout(
- currentScene = checkNotNull(sceneKeyByBlueprintId[blueprintId]),
- onChangeScene = {},
- transitions =
- transitions { sceneKeyByBlueprintId.values.forEach { sceneKey -> to(sceneKey) } },
- modifier = modifier,
- enableInterruptions = false,
- ) {
- sceneKeyByBlueprint.entries.forEach { (blueprint, sceneKey) ->
- scene(sceneKey) { with(blueprint) { Content(Modifier.fillMaxSize()) } }
- }
- }
+ val blueprint = blueprintByBlueprintId[blueprintId] ?: return
+ with(blueprint) { Content(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 7acb4d5..c241f9c 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
@@ -66,9 +66,5 @@
key = QuickSettings.SharedValues.TilesSquishiness,
)
- lockscreenContent
- .get()
- .Content(
- modifier = modifier.fillMaxSize(),
- )
+ with(lockscreenContent.get()) { Content(modifier = modifier.fillMaxSize()) }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerBaseTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerBaseTest.java
index 324534f..7986051 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerBaseTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerBaseTest.java
@@ -105,7 +105,7 @@
when(mKeyguardViewMediator.isAnimatingScreenOff()).thenReturn(false);
when(mView.getUnpausedAlpha()).thenReturn(255);
when(mShadeExpansionStateManager.addExpansionListener(any())).thenReturn(
- new ShadeExpansionChangeEvent(0, false, false, 0));
+ new ShadeExpansionChangeEvent(0, false, false));
mController = createUdfpsKeyguardViewController();
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
index 5827671..6a86801 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
@@ -376,7 +376,7 @@
// Ensure correct expansion passed in.
ShadeExpansionChangeEvent event =
new ShadeExpansionChangeEvent(
- expansion, /* expanded= */ false, /* tracking= */ true, dragDownAmount);
+ expansion, /* expanded= */ false, /* tracking= */ true);
verify(mScrimController).expand(event);
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/scrim/BouncerlessScrimControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/scrim/BouncerlessScrimControllerTest.java
index 97052a8..7cdd478 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/scrim/BouncerlessScrimControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/scrim/BouncerlessScrimControllerTest.java
@@ -59,7 +59,7 @@
final BouncerlessScrimController scrimController =
new BouncerlessScrimController(mExecutor, mPowerManager);
scrimController.addCallback(mCallback);
- scrimController.expand(new ShadeExpansionChangeEvent(.5f, true, false, 0.0f));
+ scrimController.expand(new ShadeExpansionChangeEvent(.5f, true, false));
mExecutor.runAllReady();
verify(mPowerManager).wakeUp(anyLong(), eq(PowerManager.WAKE_REASON_GESTURE), any());
verify(mCallback).onWakeup();
@@ -71,7 +71,7 @@
new BouncerlessScrimController(mExecutor, mPowerManager);
scrimController.addCallback(mCallback);
final ShadeExpansionChangeEvent expansionEvent =
- new ShadeExpansionChangeEvent(0.5f, false, false, 0.0f);
+ new ShadeExpansionChangeEvent(0.5f, false, false);
scrimController.expand(expansionEvent);
mExecutor.runAllReady();
verify(mCallback).onExpansion(eq(expansionEvent));
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImplTest.kt
index 16b68cc..ad40f8e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImplTest.kt
@@ -52,6 +52,7 @@
private val deviceEntryRepository = kosmos.fakeDeviceEntryRepository
private val deviceUnlockedInteractor = kosmos.deviceUnlockedInteractor
private val sceneInteractor = kosmos.sceneInteractor
+ private val shadeAnimationInteractor = kosmos.shadeAnimationInteractor
private val transitionState =
MutableStateFlow<ObservableTransitionState>(
ObservableTransitionState.Idle(Scenes.Lockscreen)
@@ -112,6 +113,40 @@
changeScene(Scenes.Communal) { assertThat(panelExpansion).isEqualTo(1f) }
assertThat(panelExpansion).isEqualTo(1f)
}
+
+ @Test
+ @EnableSceneContainer
+ fun shouldHideStatusBarIconsWhenExpanded_goneScene() =
+ testScope.runTest {
+ underTest = kosmos.panelExpansionInteractorImpl
+ shadeAnimationInteractor.setIsLaunchingActivity(false)
+ changeScene(Scenes.Gone)
+
+ assertThat(underTest.shouldHideStatusBarIconsWhenExpanded()).isFalse()
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun shouldHideStatusBarIconsWhenExpanded_lockscreenScene() =
+ testScope.runTest {
+ underTest = kosmos.panelExpansionInteractorImpl
+ shadeAnimationInteractor.setIsLaunchingActivity(false)
+ changeScene(Scenes.Lockscreen)
+
+ assertThat(underTest.shouldHideStatusBarIconsWhenExpanded()).isTrue()
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun shouldHideStatusBarIconsWhenExpanded_activityLaunch() =
+ testScope.runTest {
+ underTest = kosmos.panelExpansionInteractorImpl
+ changeScene(Scenes.Gone)
+ shadeAnimationInteractor.setIsLaunchingActivity(true)
+
+ assertThat(underTest.shouldHideStatusBarIconsWhenExpanded()).isFalse()
+ }
+
private fun TestScope.setUnlocked(isUnlocked: Boolean) {
val isDeviceUnlocked by collectLastValue(deviceUnlockedInteractor.isDeviceUnlocked)
deviceEntryRepository.setUnlocked(isUnlocked)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/startable/ShadeStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/startable/ShadeStartableTest.kt
index 31dacdd..52caa78 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/startable/ShadeStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/startable/ShadeStartableTest.kt
@@ -18,15 +18,32 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.compose.animation.scene.SceneKey
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository
+import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
+import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.kosmos.testScope
import com.android.systemui.res.R
+import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.scene.shared.model.fakeSceneDataSource
+import com.android.systemui.shade.ShadeExpansionChangeEvent
+import com.android.systemui.shade.ShadeExpansionListener
import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.testKosmos
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
@@ -34,11 +51,15 @@
@SmallTest
@RunWith(AndroidJUnit4::class)
class ShadeStartableTest : SysuiTestCase() {
-
private val kosmos = testKosmos()
private val testScope = kosmos.testScope
private val shadeInteractor = kosmos.shadeInteractor
+ private val sceneInteractor = kosmos.sceneInteractor
+ private val shadeExpansionStateManager = kosmos.shadeExpansionStateManager
+ private val deviceEntryRepository = kosmos.fakeDeviceEntryRepository
+ private val deviceUnlockedInteractor = kosmos.deviceUnlockedInteractor
private val fakeConfigurationRepository = kosmos.fakeConfigurationRepository
+ private val fakeSceneDataSource = kosmos.fakeSceneDataSource
private val underTest = kosmos.shadeStartable
@@ -59,4 +80,89 @@
fakeConfigurationRepository.onAnyConfigurationChange()
assertThat(shadeMode).isEqualTo(ShadeMode.Single)
}
+
+ @Test
+ @EnableSceneContainer
+ fun hydrateShadeExpansionStateManager() =
+ testScope.runTest {
+ val expansionListener = mock<ShadeExpansionListener>()
+ var latestChangeEvent: ShadeExpansionChangeEvent? = null
+ whenever(expansionListener.onPanelExpansionChanged(any())).thenAnswer {
+ latestChangeEvent = it.arguments[0] as ShadeExpansionChangeEvent
+ Unit
+ }
+ shadeExpansionStateManager.addExpansionListener(expansionListener)
+
+ underTest.start()
+
+ setUnlocked(true)
+ val transitionState =
+ MutableStateFlow<ObservableTransitionState>(
+ ObservableTransitionState.Idle(Scenes.Gone)
+ )
+ sceneInteractor.setTransitionState(transitionState)
+
+ changeScene(Scenes.Gone, transitionState)
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
+ assertThat(currentScene).isEqualTo(Scenes.Gone)
+
+ assertThat(latestChangeEvent)
+ .isEqualTo(
+ ShadeExpansionChangeEvent(
+ fraction = 0f,
+ expanded = false,
+ tracking = false,
+ )
+ )
+
+ changeScene(Scenes.Shade, transitionState) { progress ->
+ assertThat(latestChangeEvent?.fraction).isEqualTo(progress)
+ }
+ }
+
+ private fun TestScope.setUnlocked(isUnlocked: Boolean) {
+ val isDeviceUnlocked by collectLastValue(deviceUnlockedInteractor.isDeviceUnlocked)
+ deviceEntryRepository.setUnlocked(isUnlocked)
+ runCurrent()
+
+ assertThat(isDeviceUnlocked).isEqualTo(isUnlocked)
+ }
+
+ private fun TestScope.changeScene(
+ toScene: SceneKey,
+ transitionState: MutableStateFlow<ObservableTransitionState>,
+ assertDuringProgress: ((progress: Float) -> Unit) = {},
+ ) {
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val progressFlow = MutableStateFlow(0f)
+ transitionState.value =
+ ObservableTransitionState.Transition(
+ fromScene = checkNotNull(currentScene),
+ toScene = toScene,
+ progress = progressFlow,
+ isInitiatedByUserInput = true,
+ isUserInputOngoing = flowOf(true),
+ )
+ runCurrent()
+ assertDuringProgress(progressFlow.value)
+
+ progressFlow.value = 0.2f
+ runCurrent()
+ assertDuringProgress(progressFlow.value)
+
+ progressFlow.value = 0.6f
+ runCurrent()
+ assertDuringProgress(progressFlow.value)
+
+ progressFlow.value = 1f
+ runCurrent()
+ assertDuringProgress(progressFlow.value)
+
+ transitionState.value = ObservableTransitionState.Idle(toScene)
+ fakeSceneDataSource.changeScene(toScene)
+ runCurrent()
+ assertDuringProgress(progressFlow.value)
+
+ assertThat(currentScene).isEqualTo(toScene)
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
index 781a9a8..7e5205b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
@@ -36,7 +36,6 @@
import androidx.test.filters.SmallTest;
import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.LockIconViewController;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.biometrics.AuthController;
@@ -93,7 +92,6 @@
@Mock private NotificationShadeWindowViewController mNotificationShadeWindowViewController;
@Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@Mock private ShadeLockscreenInteractor mShadeLockscreenInteractor;
- @Mock private LockIconViewController mLockIconViewController;
@Mock private View mAmbientIndicationContainer;
@Mock private BiometricUnlockController mBiometricUnlockController;
@Mock private AuthController mAuthController;
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModelTest.kt
index 8e92557..2cc1ad3 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModelTest.kt
@@ -84,8 +84,17 @@
runCurrent()
- verify(activityStarter).startActivity(capture(intentCaptor), eq(true),
- capture(activityStartedCaptor))
+ verify(activityStarter)
+ .startActivityDismissingKeyguard(
+ /* intent = */ capture(intentCaptor),
+ /* onlyProvisioned = */ eq(false),
+ /* dismissShade = */ eq(true),
+ /* disallowEnterPictureInPictureWhileLaunching = */ eq(false),
+ /* callback = */ capture(activityStartedCaptor),
+ /* flags = */ eq(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT),
+ /* animationController = */ eq(null),
+ /* userHandle = */ eq(null),
+ )
assertThat(intentCaptor.value.action).isEqualTo(Settings.ACTION_SOUND_SETTINGS)
activityStartedCaptor.value.onActivityStarted(ActivityManager.START_SUCCESS)
diff --git a/packages/SystemUI/src/com/android/keyguard/EmptyLockIconViewController.kt b/packages/SystemUI/src/com/android/keyguard/EmptyLockIconViewController.kt
new file mode 100644
index 0000000..b792db3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/EmptyLockIconViewController.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard
+
+import android.view.MotionEvent
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.ui.view.KeyguardRootView
+import com.android.systemui.res.R
+import dagger.Lazy
+import javax.inject.Inject
+
+/**
+ * Lock icon view logic now lives in DeviceEntryIconViewBinder and ViewModels. Icon is positioned in
+ * [com.android.systemui.keyguard.ui.view.layout.sections.DefaultDeviceEntrySection].
+ *
+ * This class is to bridge the gap between the logic when the DeviceEntryUdfpsRefactor is enabled
+ * and the KeyguardBottomAreaRefactor is NOT enabled. This class can and should be removed when both
+ * flags are enabled.
+ */
+@SysUISingleton
+class EmptyLockIconViewController
+@Inject
+constructor(
+ private val keyguardRootView: Lazy<KeyguardRootView>,
+) : LockIconViewController {
+ private val deviceEntryIconViewId = R.id.device_entry_icon_view
+ override fun setLockIconView(lockIconView: LockIconView) {
+ // no-op
+ }
+
+ override fun getTop(): Float {
+ return keyguardRootView.get().getViewById(deviceEntryIconViewId)?.top?.toFloat() ?: 0f
+ }
+
+ override fun getBottom(): Float {
+ return keyguardRootView.get().getViewById(deviceEntryIconViewId)?.bottom?.toFloat() ?: 0f
+ }
+
+ override fun dozeTimeTick() {
+ // no-op
+ }
+
+ override fun setAlpha(alpha: Float) {
+ // no-op
+ }
+
+ override fun willHandleTouchWhileDozing(event: MotionEvent): Boolean {
+ return false
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LegacyLockIconViewController.java
similarity index 99%
rename from packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
rename to packages/SystemUI/src/com/android/keyguard/LegacyLockIconViewController.java
index 985f6c8..4e5df35 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LegacyLockIconViewController.java
@@ -98,7 +98,7 @@
* icon will show a set distance from the bottom of the device.
*/
@SysUISingleton
-public class LockIconViewController implements Dumpable {
+public class LegacyLockIconViewController implements Dumpable, LockIconViewController {
private static final String TAG = "LockIconViewController";
private static final float sDefaultDensity =
(float) DisplayMetrics.DENSITY_DEVICE_STABLE / (float) DisplayMetrics.DENSITY_DEFAULT;
@@ -189,7 +189,7 @@
};
@Inject
- public LockIconViewController(
+ public LegacyLockIconViewController(
@NonNull StatusBarStateController statusBarStateController,
@NonNull KeyguardUpdateMonitor keyguardUpdateMonitor,
@NonNull KeyguardViewController keyguardViewController,
@@ -262,6 +262,7 @@
/** Sets the LockIconView to the controller and rebinds any that depend on it. */
@SuppressLint("ClickableViewAccessibility")
+ @Override
public void setLockIconView(LockIconView lockIconView) {
mView = lockIconView;
mView.setAccessibilityDelegate(mAccessibilityDelegate);
@@ -344,10 +345,12 @@
}
}
+ @Override
public float getTop() {
return mView.getLocationTop();
}
+ @Override
public float getBottom() {
return mView.getLocationBottom();
}
@@ -499,6 +502,7 @@
}
/** Every minute, update the aod icon's burn in offset */
+ @Override
public void dozeTimeTick() {
updateBurnInOffsets();
}
@@ -774,6 +778,7 @@
/**
* Set the alpha of this view.
*/
+ @Override
public void setAlpha(float alpha) {
mView.setAlpha(alpha);
}
@@ -823,6 +828,7 @@
/**
* Whether the lock icon will handle a touch while dozing.
*/
+ @Override
public boolean willHandleTouchWhileDozing(MotionEvent event) {
// is in lock icon area
mView.getHitRect(mSensorTouchLocation);
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.kt b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.kt
new file mode 100644
index 0000000..10d5a0c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard
+
+import android.view.MotionEvent
+
+/** Controls the [LockIconView]. */
+interface LockIconViewController {
+ fun setLockIconView(lockIconView: LockIconView)
+ fun getTop(): Float
+ fun getBottom(): Float
+ fun dozeTimeTick()
+ fun setAlpha(alpha: Float)
+ fun willHandleTouchWhileDozing(event: MotionEvent): Boolean
+}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIService.java b/packages/SystemUI/src/com/android/systemui/SystemUIService.java
index b26be0c..0cc3be2 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIService.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIService.java
@@ -99,9 +99,10 @@
if (Build.IS_DEBUGGABLE) {
// b/71353150 - looking for leaked binder proxies
BinderInternal.nSetBinderProxyCountEnabled(true);
- BinderInternal.nSetBinderProxyCountWatermarks(1000,900);
+ BinderInternal.nSetBinderProxyCountWatermarks(
+ /* high= */ 1000, /* low= */ 900, /* warning= */ 950);
BinderInternal.setBinderProxyCountCallback(
- new BinderInternal.BinderProxyLimitListener() {
+ new BinderInternal.BinderProxyCountEventListener() {
@Override
public void onLimitReached(int uid) {
Slog.w(SystemUIApplication.TAG,
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java
index 1f5a0bf..be75e10 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java
@@ -36,7 +36,6 @@
import androidx.recyclerview.widget.RecyclerView;
import com.android.internal.accessibility.dialog.AccessibilityTarget;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.modules.expresslog.Counter;
import com.android.systemui.Flags;
import com.android.systemui.util.settings.SecureSettings;
@@ -418,18 +417,11 @@
onPositionChanged();
}
- void incrementTexMetricForAllTargets(String metric) {
+ void incrementTexMetric(String metric) {
if (!Flags.floatingMenuDragToEdit()) {
return;
}
- for (AccessibilityTarget target : mTargetFeatures) {
- incrementTexMetric(metric, target.getUid());
- }
- }
-
- @VisibleForTesting
- void incrementTexMetric(String metric, int uid) {
- Counter.logIncrementWithUid(metric, uid);
+ Counter.logIncrement(metric);
}
private InstantInsetLayerDrawable getContainerViewInsetLayer() {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
index 85bf784..86279be 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
@@ -105,14 +105,14 @@
*
* <p>Defined in frameworks/proto_logging/stats/express/catalog/accessibility.cfg.
*/
- static final String TEX_METRIC_DISMISS = "accessibility.value_fab_shortcut_action_dismiss";
+ static final String TEX_METRIC_DISMISS = "accessibility.value_fab_shortcut_dismiss";
/**
* Counter indicating the FAB was dragged to the Edit action button.
*
* <p>Defined in frameworks/proto_logging/stats/express/catalog/accessibility.cfg.
*/
- static final String TEX_METRIC_EDIT = "accessibility.value_fab_shortcut_action_edit";
+ static final String TEX_METRIC_EDIT = "accessibility.value_fab_shortcut_edit";
private final WindowManager mWindowManager;
private final MenuView mMenuView;
@@ -492,11 +492,11 @@
} else {
hideMenuAndShowMessage();
}
- mMenuView.incrementTexMetricForAllTargets(TEX_METRIC_DISMISS);
+ mMenuView.incrementTexMetric(TEX_METRIC_DISMISS);
} else if (id == R.id.action_edit
&& Flags.floatingMenuDragToEdit()) {
gotoEditScreen();
- mMenuView.incrementTexMetricForAllTargets(TEX_METRIC_EDIT);
+ mMenuView.incrementTexMetric(TEX_METRIC_EDIT);
}
mDismissView.hide();
mDragToInteractView.hide();
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java
new file mode 100644
index 0000000..4733d06
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility.hearingaid;
+
+import com.android.systemui.statusbar.phone.SystemUIDialog;
+
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
+
+/**
+ * Dialog for showing hearing devices controls.
+ */
+public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate{
+
+ private final SystemUIDialog.Factory mSystemUIDialogFactory;
+
+ private SystemUIDialog mDialog;
+
+ /** Factory to create a {@link HearingDevicesDialogDelegate} dialog instance. */
+ @AssistedFactory
+ public interface Factory {
+ /** Create a {@link HearingDevicesDialogDelegate} instance */
+ HearingDevicesDialogDelegate create();
+ }
+
+ @AssistedInject
+ public HearingDevicesDialogDelegate(
+ SystemUIDialog.Factory systemUIDialogFactory) {
+ mSystemUIDialogFactory = systemUIDialogFactory;
+ }
+
+ @Override
+ public SystemUIDialog createDialog() {
+ SystemUIDialog dialog = mSystemUIDialogFactory.create(this);
+
+ if (mDialog != null) {
+ mDialog.dismiss();
+ }
+ mDialog = dialog;
+
+ return dialog;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogManager.java b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogManager.java
new file mode 100644
index 0000000..c83043e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogManager.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility.hearingaid;
+
+import android.util.Log;
+import android.view.View;
+
+import com.android.internal.jank.InteractionJankMonitor;
+import com.android.systemui.animation.DialogCuj;
+import com.android.systemui.animation.DialogTransitionAnimator;
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.statusbar.phone.SystemUIDialog;
+
+import javax.inject.Inject;
+
+/**
+ * Factory to create {@link HearingDevicesDialogDelegate} objects and manage its lifecycle.
+ */
+@SysUISingleton
+public class HearingDevicesDialogManager {
+
+ private static final boolean DEBUG = true;
+ private static final String TAG = "HearingDevicesDialogManager";
+ private static final String INTERACTION_JANK_TAG = "hearing_devices_tile";
+ private SystemUIDialog mDialog;
+ private final DialogTransitionAnimator mDialogTransitionAnimator;
+ private final HearingDevicesDialogDelegate.Factory mDialogFactory;
+
+ @Inject
+ public HearingDevicesDialogManager(
+ DialogTransitionAnimator dialogTransitionAnimator,
+ HearingDevicesDialogDelegate.Factory dialogFactory) {
+ mDialogTransitionAnimator = dialogTransitionAnimator;
+ mDialogFactory = dialogFactory;
+ }
+
+ /**
+ * Shows the dialog.
+ *
+ * @param view The view from which the dialog is shown.
+ */
+ public void showDialog(View view) {
+ if (mDialog != null) {
+ if (DEBUG) {
+ Log.d(TAG, "HearingDevicesDialog already showing. Destroy it first.");
+ }
+ destroyDialog();
+ }
+ mDialog = mDialogFactory.create().createDialog();
+
+ if (view != null) {
+ mDialogTransitionAnimator.showFromView(mDialog, view,
+ new DialogCuj(InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN,
+ INTERACTION_JANK_TAG),
+ true);
+ } else {
+ mDialog.show();
+ }
+ }
+
+ private void destroyDialog() {
+ mDialog.dismiss();
+ mDialog = null;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
index 86b254b..246d5d9 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
@@ -81,6 +81,7 @@
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.shareIn
+import kotlinx.coroutines.flow.stateIn
/** Encapsulates business-logic related to communal mode. */
@OptIn(ExperimentalCoroutinesApi::class)
@@ -239,10 +240,14 @@
* This will not be true while transitioning to the hub and will turn false immediately when a
* swipe to exit the hub starts.
*/
- val isIdleOnCommunal: Flow<Boolean> =
- communalRepository.transitionState.map {
- it is ObservableTransitionState.Idle && it.scene == CommunalScenes.Communal
- }
+ val isIdleOnCommunal: StateFlow<Boolean> =
+ communalRepository.transitionState
+ .map { it is ObservableTransitionState.Idle && it.scene == CommunalScenes.Communal }
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.Eagerly,
+ initialValue = false,
+ )
/**
* Flow that emits a boolean if any portion of the communal UI is visible at all.
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/DeviceEntryModule.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/DeviceEntryModule.kt
index 71b5ab2..b8c03c0 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/DeviceEntryModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/DeviceEntryModule.kt
@@ -1,9 +1,32 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.systemui.deviceentry
+import com.android.keyguard.EmptyLockIconViewController
+import com.android.keyguard.LegacyLockIconViewController
+import com.android.keyguard.LockIconViewController
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.deviceentry.data.repository.DeviceEntryRepositoryModule
import com.android.systemui.deviceentry.data.repository.FaceWakeUpTriggersConfigModule
+import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
+import dagger.Lazy
import dagger.Module
+import dagger.Provides
import dagger.multibindings.Multibinds
@Module(
@@ -18,4 +41,19 @@
* A set of DeviceEntryIconTransitions. Ensures that this can be injected even if it's empty.
*/
@Multibinds abstract fun deviceEntryIconTransitionSet(): Set<DeviceEntryIconTransition>
+
+ companion object {
+ @Provides
+ @SysUISingleton
+ fun provideLockIconViewController(
+ legacyLockIconViewController: Lazy<LegacyLockIconViewController>,
+ emptyLockIconViewController: Lazy<EmptyLockIconViewController>,
+ ): LockIconViewController {
+ return if (DeviceEntryUdfpsRefactor.isEnabled) {
+ emptyLockIconViewController.get()
+ } else {
+ legacyLockIconViewController.get()
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java
index 7f3b5eb..926f7f1 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java
@@ -172,19 +172,18 @@
final float screenTravelPercentage = Math.abs(e1.getY() - e2.getY())
/ mTouchSession.getBounds().height();
setPanelExpansion(mBouncerInitiallyShowing
- ? screenTravelPercentage : 1 - screenTravelPercentage, dragDownAmount);
+ ? screenTravelPercentage : 1 - screenTravelPercentage);
return true;
}
};
- private void setPanelExpansion(float expansion, float dragDownAmount) {
+ private void setPanelExpansion(float expansion) {
mCurrentExpansion = expansion;
ShadeExpansionChangeEvent event =
new ShadeExpansionChangeEvent(
/* fraction= */ mCurrentExpansion,
/* expanded= */ mExpanded,
- /* tracking= */ true,
- /* dragDownPxAmount= */ dragDownAmount);
+ /* tracking= */ true);
mCurrentScrimController.expand(event);
}
@@ -333,7 +332,7 @@
animation -> {
float expansionFraction = (float) animation.getAnimatedValue();
float dragDownAmount = expansionFraction * expansionHeight;
- setPanelExpansion(expansionFraction, dragDownAmount);
+ setPanelExpansion(expansionFraction);
});
if (!mBouncerInitiallyShowing
&& targetExpansion == KeyguardBouncerConstants.EXPANSION_VISIBLE) {
diff --git a/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffectViewBinder.kt b/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffectViewBinder.kt
index 1705909..f4998a7 100644
--- a/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffectViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffectViewBinder.kt
@@ -18,10 +18,10 @@
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
+import com.android.app.tracing.coroutines.launch
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.qs.tileimpl.QSTileViewImpl
import kotlinx.coroutines.DisposableHandle
-import kotlinx.coroutines.launch
class QSLongPressEffectViewBinder {
@@ -31,16 +31,18 @@
fun bind(
tile: QSTileViewImpl,
+ tileSpec: String?,
effect: QSLongPressEffect?,
) {
if (effect == null) return
handle =
tile.repeatWhenAttached {
- repeatOnLifecycle(Lifecycle.State.STARTED) {
+ repeatOnLifecycle(Lifecycle.State.CREATED) {
effect.scope = this
+ val tag = "${tileSpec ?: "unknownTileSpec"}#LongPressEffect"
- launch {
+ launch("$tag#progress") {
effect.effectProgress.collect { progress ->
progress?.let {
if (it == 0f) {
@@ -51,7 +53,7 @@
}
}
- launch {
+ launch("$tag#action") {
effect.actionType.collect { action ->
action?.let {
when (it) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
index fa845c7..30beca7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
@@ -29,11 +29,14 @@
import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
import androidx.constraintlayout.widget.ConstraintSet.START
import androidx.constraintlayout.widget.ConstraintSet.TOP
+import com.android.compose.animation.scene.SceneKey
+import com.android.compose.animation.scene.SceneTransitionLayout
+import com.android.compose.animation.scene.transitions
import com.android.internal.jank.InteractionJankMonitor
import com.android.keyguard.KeyguardStatusView
import com.android.keyguard.KeyguardStatusViewController
+import com.android.keyguard.LegacyLockIconViewController
import com.android.keyguard.LockIconView
-import com.android.keyguard.LockIconViewController
import com.android.keyguard.dagger.KeyguardStatusViewComponent
import com.android.systemui.CoreStartable
import com.android.systemui.common.ui.ConfigurationState
@@ -92,7 +95,7 @@
private val configuration: ConfigurationState,
private val context: Context,
private val keyguardIndicationController: KeyguardIndicationController,
- private val lockIconViewController: Lazy<LockIconViewController>,
+ private val lockIconViewController: Lazy<LegacyLockIconViewController>,
private val shadeInteractor: ShadeInteractor,
private val interactionJankMonitor: InteractionJankMonitor,
private val deviceEntryHapticsInteractor: DeviceEntryHapticsInteractor,
@@ -109,6 +112,7 @@
private var rootViewHandle: DisposableHandle? = null
private var indicationAreaHandle: DisposableHandle? = null
+ private val sceneKey = SceneKey("root-view-scene-key")
var keyguardStatusViewController: KeyguardStatusViewController? = null
get() {
@@ -219,12 +223,25 @@
blueprints.mapNotNull { it as? ComposableLockscreenSceneBlueprint }.toSet()
return ComposeView(context).apply {
setContent {
- LockscreenContent(
- viewModel = viewModel,
- blueprints = sceneBlueprints,
- clockInteractor = clockInteractor
- )
- .Content(modifier = Modifier.fillMaxSize())
+ // STL is used solely to provide a SceneScope to enable us to invoke SceneScope
+ // composables.
+ SceneTransitionLayout(
+ currentScene = sceneKey,
+ onChangeScene = {},
+ transitions = transitions {},
+ ) {
+ scene(sceneKey) {
+ with(
+ LockscreenContent(
+ viewModel = viewModel,
+ blueprints = sceneBlueprints,
+ clockInteractor = clockInteractor
+ )
+ ) {
+ Content(modifier = Modifier.fillMaxSize())
+ }
+ }
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt
index 88eadd7..b3d9a76 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt
@@ -92,7 +92,8 @@
walletController.setupWalletChangeObservers(
callback,
QuickAccessWalletController.WalletChangeEvent.WALLET_PREFERENCE_CHANGE,
- QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE
+ QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE,
+ QuickAccessWalletController.WalletChangeEvent.DEFAULT_WALLET_APP_CHANGE
)
withContext(backgroundDispatcher) {
@@ -104,7 +105,8 @@
awaitClose {
walletController.unregisterWalletChangeObservers(
QuickAccessWalletController.WalletChangeEvent.WALLET_PREFERENCE_CHANGE,
- QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE
+ QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE,
+ QuickAccessWalletController.WalletChangeEvent.DEFAULT_WALLET_APP_CHANGE
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/backup/KeyguardQuickAffordanceBackupHelper.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/backup/KeyguardQuickAffordanceBackupHelper.kt
index fa6efa5..f763e62 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/backup/KeyguardQuickAffordanceBackupHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/backup/KeyguardQuickAffordanceBackupHelper.kt
@@ -17,14 +17,17 @@
package com.android.systemui.keyguard.domain.backup
+import android.app.backup.BackupDataInputStream
import android.app.backup.SharedPreferencesBackupHelper
import android.content.Context
+import android.util.Log
+import com.android.app.tracing.traceSection
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceSelectionManager
import com.android.systemui.settings.UserFileManagerImpl
/** Handles backup & restore for keyguard quick affordances. */
class KeyguardQuickAffordanceBackupHelper(
- context: Context,
+ private val context: Context,
userId: Int,
) :
SharedPreferencesBackupHelper(
@@ -34,4 +37,17 @@
fileName = KeyguardQuickAffordanceSelectionManager.FILE_NAME,
)
.getPath()
- )
+ ) {
+
+ override fun restoreEntity(data: BackupDataInputStream?) {
+ Log.d(TAG, "Starting restore for ${data?.key} for user ${context.userId}")
+ traceSection("$TAG File restore: ${data?.key}") {
+ super.restoreEntity(data)
+ }
+ Log.d(TAG, "Finished restore for ${data?.key} for user ${context.userId}")
+ }
+
+ companion object {
+ private const val TAG = "KeyguardQuickAffordanceBackupHelper"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
index 1b91c49..87324a2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
@@ -20,6 +20,7 @@
import android.content.Context
import com.android.settingslib.Utils
import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
import javax.inject.Inject
@@ -34,6 +35,7 @@
/** Models the UI state for the device entry icon background view. */
@Suppress("WHEN_ENUM_CAN_BE_NULL_IN_JAVA")
@ExperimentalCoroutinesApi
+@SysUISingleton
class DeviceEntryBackgroundViewModel
@Inject
constructor(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt
index 6281097..0aa6d12 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt
@@ -21,6 +21,7 @@
import com.android.settingslib.Utils
import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor
import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
@@ -39,6 +40,7 @@
/** Models the UI state for the device entry icon foreground view (displayed icon). */
@ExperimentalCoroutinesApi
+@SysUISingleton
class DeviceEntryForegroundViewModel
@Inject
constructor(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
index bc4fd1c..49fffdd 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
@@ -19,6 +19,7 @@
import android.animation.FloatEvaluator
import android.animation.IntEvaluator
import com.android.keyguard.KeyguardViewController
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
import com.android.systemui.deviceentry.domain.interactor.DeviceEntrySourceInteractor
@@ -52,6 +53,7 @@
/** Models the UI state for the containing device entry icon & long-press handling view. */
@ExperimentalCoroutinesApi
+@SysUISingleton
class DeviceEntryIconViewModel
@Inject
constructor(
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/BaseMediaProjectionPermissionDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/BaseMediaProjectionPermissionDialogDelegate.kt
index 1983a67..dba0173 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/BaseMediaProjectionPermissionDialogDelegate.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/BaseMediaProjectionPermissionDialogDelegate.kt
@@ -53,19 +53,17 @@
private lateinit var cancelButton: TextView
private lateinit var warning: TextView
private lateinit var screenShareModeSpinner: Spinner
- private var hasCancelBeenLogged: Boolean = false
protected lateinit var dialog: AlertDialog
+ private var shouldLogCancel: Boolean = true
var selectedScreenShareOption: ScreenShareOption = screenShareOptions.first()
@CallSuper
override fun onStop(dialog: T) {
// onStop can be called multiple times and we only want to log once.
- if (hasCancelBeenLogged) {
- return
+ if (shouldLogCancel) {
+ mediaProjectionMetricsLogger.notifyProjectionRequestCancelled(hostUid)
+ shouldLogCancel = false
}
-
- mediaProjectionMetricsLogger.notifyProjectionRequestCancelled(hostUid)
- hasCancelBeenLogged = true
}
@CallSuper
@@ -140,7 +138,10 @@
}
protected fun setStartButtonOnClickListener(listener: View.OnClickListener?) {
- startButton.setOnClickListener(listener)
+ startButton.setOnClickListener { view ->
+ shouldLogCancel = false
+ listener?.onClick(view)
+ }
}
protected fun setCancelButtonOnClickListener(listener: View.OnClickListener?) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
index 1aef920..8d3500a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
@@ -29,6 +29,7 @@
import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.ReduceBrightColorsController;
import com.android.systemui.qs.external.QSExternalModule;
+import com.android.systemui.qs.panels.dagger.PanelsModule;
import com.android.systemui.qs.pipeline.dagger.QSPipelineModule;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.qs.tiles.di.QSTilesModule;
@@ -44,21 +45,22 @@
import com.android.systemui.statusbar.policy.WalletController;
import com.android.systemui.util.settings.SecureSettings;
-import java.util.Map;
-
-import javax.inject.Named;
-
import dagger.Binds;
import dagger.Module;
import dagger.Provides;
import dagger.multibindings.Multibinds;
+import java.util.Map;
+
+import javax.inject.Named;
+
/**
* Module for QS dependencies
*/
@Module(subcomponents = {QSFragmentComponent.class, QSSceneComponent.class},
includes = {
MediaModule.class,
+ PanelsModule.class,
QSExternalModule.class,
QSFlagsModule.class,
QSHostModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt
new file mode 100644
index 0000000..1307296
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.panels.dagger
+
+import com.android.systemui.qs.panels.data.repository.IconTilesRepository
+import com.android.systemui.qs.panels.data.repository.IconTilesRepositoryImpl
+import dagger.Binds
+import dagger.Module
+
+@Module
+interface PanelsModule {
+ @Binds fun bindIconTilesRepository(impl: IconTilesRepositoryImpl): IconTilesRepository
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/IconTilesRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/IconTilesRepository.kt
new file mode 100644
index 0000000..92f87e7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/IconTilesRepository.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.panels.data.repository
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flowOf
+
+/** Repository for retrieving the list of [TileSpec] to be displayed as icons. */
+interface IconTilesRepository {
+ val iconTilesSpecs: Flow<Set<TileSpec>>
+}
+
+@SysUISingleton
+class IconTilesRepositoryImpl @Inject constructor() : IconTilesRepository {
+
+ /** Set of toggleable tiles that are suitable for being shown as an icon. */
+ override val iconTilesSpecs: Flow<Set<TileSpec>> =
+ flowOf(
+ setOf(
+ TileSpec.create("airplane"),
+ TileSpec.create("battery"),
+ TileSpec.create("cameratoggle"),
+ TileSpec.create("cast"),
+ TileSpec.create("color_correction"),
+ TileSpec.create("inversion"),
+ TileSpec.create("saver"),
+ TileSpec.create("dnd"),
+ TileSpec.create("flashlight"),
+ TileSpec.create("location"),
+ TileSpec.create("mictoggle"),
+ TileSpec.create("nfc"),
+ TileSpec.create("night"),
+ TileSpec.create("rotation")
+ )
+ )
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractor.kt
new file mode 100644
index 0000000..367c670
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractor.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.panels.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.qs.panels.data.repository.IconTilesRepository
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+
+/** Interactor for retrieving the list of [TileSpec] to be displayed as icons. */
+@SysUISingleton
+class IconTilesInteractor @Inject constructor(private val repo: IconTilesRepository) {
+ val iconTilesSpecs: Flow<Set<TileSpec>> = repo.iconTilesSpecs
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
index 2360f27..3004485 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
@@ -620,7 +620,7 @@
showRippleEffect = false
setOnTouchListener(longPressEffect)
if (!longPressEffectViewBinder.isBound) {
- longPressEffectViewBinder.bind(this, longPressEffect)
+ longPressEffectViewBinder.bind(this, state.spec, longPressEffect)
}
} else {
// Long-press effects might have been enabled before but the new state does not
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HearingDevicesTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HearingDevicesTile.java
index 1fb701e..81a2026 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HearingDevicesTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HearingDevicesTile.java
@@ -26,6 +26,7 @@
import com.android.internal.logging.MetricsLogger;
import com.android.systemui.Flags;
+import com.android.systemui.accessibility.hearingaid.HearingDevicesDialogManager;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
@@ -45,6 +46,8 @@
public static final String TILE_SPEC = "hearing_devices";
+ private final HearingDevicesDialogManager mDialogManager;
+
@Inject
public HearingDevicesTile(
QSHost host,
@@ -55,10 +58,12 @@
MetricsLogger metricsLogger,
StatusBarStateController statusBarStateController,
ActivityStarter activityStarter,
- QSLogger qsLogger
+ QSLogger qsLogger,
+ HearingDevicesDialogManager hearingDevicesDialogManager
) {
super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger,
statusBarStateController, activityStarter, qsLogger);
+ mDialogManager = hearingDevicesDialogManager;
}
@Override
@@ -68,7 +73,7 @@
@Override
protected void handleClick(@Nullable View view) {
-
+ mUiHandler.post(() -> mDialogManager.showDialog(view));
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
index 1b73225..e1b742e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
@@ -182,12 +182,19 @@
@Override
public boolean isAvailable() {
+ if (isWalletRoleAvailable()) {
+ return !mPackageManager.hasSystemFeature(FEATURE_CHROME_OS);
+ }
return mPackageManager.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)
&& !mPackageManager.hasSystemFeature(FEATURE_CHROME_OS)
&& mSecureSettings.getStringForUser(NFC_PAYMENT_DEFAULT_COMPONENT,
UserHandle.USER_CURRENT) != null;
}
+ private boolean isWalletRoleAvailable() {
+ return mHost.getUserId() == UserHandle.USER_SYSTEM && mController.isWalletRoleAvailable();
+ }
+
@Nullable
@Override
public Intent getLongClickIntent() {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelView.java
index c501d88..6bf5535 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelView.java
@@ -27,6 +27,8 @@
import android.view.MotionEvent;
import android.widget.FrameLayout;
+import com.android.systemui.scene.shared.flag.SceneContainerFlag;
+
/** The shade view. */
public final class NotificationPanelView extends FrameLayout {
static final boolean DEBUG = false;
@@ -41,14 +43,20 @@
public NotificationPanelView(Context context, AttributeSet attrs) {
super(context, attrs);
- setWillNotDraw(!DEBUG);
- mAlphaPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
+ if (!SceneContainerFlag.isEnabled()) {
+ setWillNotDraw(!DEBUG);
+ mAlphaPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
- setBackgroundColor(Color.TRANSPARENT);
+ setBackgroundColor(Color.TRANSPARENT);
+ }
}
@Override
public void onRtlPropertiesChanged(int layoutDirection) {
+ if (SceneContainerFlag.isEnabled()) {
+ super.onRtlPropertiesChanged(layoutDirection);
+ return;
+ }
if (mRtlChangeListener != null) {
mRtlChangeListener.onRtlPropertielsChanged(layoutDirection);
}
@@ -56,14 +64,19 @@
@Override
public boolean shouldDelayChildPressedState() {
+ if (SceneContainerFlag.isEnabled()) {
+ return super.shouldDelayChildPressedState();
+ }
return true;
}
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
- if (mCurrentPanelAlpha != 255) {
- canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), mAlphaPaint);
+ if (!SceneContainerFlag.isEnabled()) {
+ if (mCurrentPanelAlpha != 255) {
+ canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), mAlphaPaint);
+ }
}
}
@@ -83,6 +96,9 @@
@Override
public boolean hasOverlappingRendering() {
+ if (SceneContainerFlag.isEnabled()) {
+ return super.hasOverlappingRendering();
+ }
return !mDozing;
}
@@ -102,6 +118,9 @@
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
+ if (SceneContainerFlag.isEnabled()) {
+ return super.onInterceptTouchEvent(event);
+ }
return mTouchHandler.onInterceptTouchEvent(event);
}
@@ -113,7 +132,9 @@
@Override
public void dispatchConfigurationChanged(Configuration newConfig) {
super.dispatchConfigurationChanged(newConfig);
- mOnConfigurationChangedListener.onConfigurationChanged(newConfig);
+ if (!SceneContainerFlag.isEnabled()) {
+ mOnConfigurationChangedListener.onConfigurationChanged(newConfig);
+ }
}
/** Callback for right-to-left setting changes. */
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index e4f5aeb..fa5f30f 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -96,12 +96,12 @@
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.LatencyTracker;
import com.android.keyguard.ActiveUnlockConfig;
+import com.android.keyguard.LockIconViewController;
import com.android.keyguard.KeyguardClockSwitch.ClockSize;
import com.android.keyguard.KeyguardStatusView;
import com.android.keyguard.KeyguardStatusViewController;
import com.android.keyguard.KeyguardUnfoldTransition;
import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.LockIconViewController;
import com.android.keyguard.dagger.KeyguardQsUserSwitchComponent;
import com.android.keyguard.dagger.KeyguardStatusBarViewComponent;
import com.android.keyguard.dagger.KeyguardStatusViewComponent;
@@ -982,6 +982,7 @@
});
mAlternateBouncerInteractor = alternateBouncerInteractor;
dumpManager.registerDumpable(this);
+ SceneContainerFlag.assertInLegacyMode();
}
private void unlockAnimationFinished() {
@@ -3555,9 +3556,9 @@
}
@Override
- public ViewPropertyAnimator fadeOut(long startDelayMs, long durationMs, Runnable endAction) {
+ public void fadeOut(long startDelayMs, long durationMs, Runnable endAction) {
mView.animate().cancel();
- return mView.animate().alpha(0).setStartDelay(startDelayMs).setDuration(
+ mView.animate().alpha(0).setStartDelay(startDelayMs).setDuration(
durationMs).setInterpolator(Interpolators.ALPHA_OUT).withLayer().withEndAction(
endAction);
}
@@ -4121,9 +4122,10 @@
@Override
public void updateExpansionAndVisibility() {
- mShadeExpansionStateManager.onPanelExpansionChanged(
- mExpandedFraction, isExpanded(), isTracking(), mExpansionDragDownAmountPx);
-
+ if (!SceneContainerFlag.isEnabled()) {
+ mShadeExpansionStateManager.onPanelExpansionChanged(
+ mExpandedFraction, isExpanded(), isTracking());
+ }
updateVisibility();
}
@@ -4159,7 +4161,8 @@
}
/** Sends an external (e.g. Status Bar) intercept touch event to the Shade touch handler. */
- boolean handleExternalInterceptTouch(MotionEvent event) {
+ @Override
+ public boolean handleExternalInterceptTouch(MotionEvent event) {
try {
mUseExternalTouch = true;
return mTouchHandler.onInterceptTouchEvent(event);
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
index 59da8f1..324dfdf 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -52,6 +52,7 @@
import com.android.systemui.keyguard.shared.model.TransitionState;
import com.android.systemui.keyguard.shared.model.TransitionStep;
import com.android.systemui.res.R;
+import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor;
import com.android.systemui.shared.animation.DisableSubpixelTextTransitionListener;
import com.android.systemui.statusbar.DragDownHelper;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
@@ -132,7 +133,8 @@
private DragDownHelper mDragDownHelper;
private boolean mExpandingBelowNotch;
private final DockManager mDockManager;
- private final NotificationPanelViewController mNotificationPanelViewController;
+ private final ShadeViewController mShadeViewController;
+ private final PanelExpansionInteractor mPanelExpansionInteractor;
private final ShadeExpansionStateManager mShadeExpansionStateManager;
private boolean mIsTrackingBarGesture = false;
@@ -154,7 +156,8 @@
DockManager dockManager,
NotificationShadeDepthController depthController,
NotificationShadeWindowView notificationShadeWindowView,
- NotificationPanelViewController notificationPanelViewController,
+ ShadeViewController shadeViewController,
+ PanelExpansionInteractor panelExpansionInteractor,
ShadeExpansionStateManager shadeExpansionStateManager,
NotificationStackScrollLayoutController notificationStackScrollLayoutController,
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
@@ -187,7 +190,8 @@
mStatusBarStateController = statusBarStateController;
mView = notificationShadeWindowView;
mDockManager = dockManager;
- mNotificationPanelViewController = notificationPanelViewController;
+ mShadeViewController = shadeViewController;
+ mPanelExpansionInteractor = panelExpansionInteractor;
mShadeExpansionStateManager = shadeExpansionStateManager;
mDepthController = depthController;
mNotificationStackScrollLayoutController = notificationStackScrollLayoutController;
@@ -374,7 +378,7 @@
}
if (!mIsTrackingBarGesture && isDown
- && mNotificationPanelViewController.isFullyCollapsed()) {
+ && mPanelExpansionInteractor.isFullyCollapsed()) {
float x = ev.getRawX();
float y = ev.getRawY();
if (mStatusBarViewController.touchIsWithinView(x, y)) {
@@ -447,7 +451,7 @@
} else {
bouncerShowing = mService.isBouncerShowing();
}
- if (mNotificationPanelViewController.isFullyExpanded()
+ if (mPanelExpansionInteractor.isFullyExpanded()
&& !bouncerShowing
&& !mStatusBarStateController.isDozing()) {
if (mDragDownHelper.isDragDownEnabled()) {
@@ -503,7 +507,7 @@
cancellation.setAction(MotionEvent.ACTION_CANCEL);
mStackScrollLayout.onInterceptTouchEvent(cancellation);
if (!MigrateClocksToBlueprint.isEnabled()) {
- mNotificationPanelViewController.handleExternalInterceptTouch(cancellation);
+ mShadeViewController.handleExternalInterceptTouch(cancellation);
}
cancellation.recycle();
}
@@ -522,7 +526,7 @@
// we still want to finish our drag down gesture when locking the screen
handled |= mDragDownHelper.onTouchEvent(ev) || handled;
}
- if (!handled && mNotificationPanelViewController.handleExternalTouch(ev)) {
+ if (!handled && mShadeViewController.handleExternalTouch(ev)) {
return true;
}
} else {
@@ -611,7 +615,7 @@
// Since NotificationStackScrollLayout is now a sibling of notification_panel, we need
// to also ask NotificationPanelViewController directly, in order to process swipe up
// events originating from notifications
- if (mNotificationPanelViewController.handleExternalInterceptTouch(ev)) {
+ if (mShadeViewController.handleExternalInterceptTouch(ev)) {
mShadeLogger.d("NSWVC: NPVC intercepted");
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionChangeEvent.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionChangeEvent.kt
index 71dfafa..d9c1f0a 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionChangeEvent.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionChangeEvent.kt
@@ -23,7 +23,5 @@
/** Whether the panel should be considered expanded */
val expanded: Boolean,
/** Whether the user is actively dragging the panel. */
- val tracking: Boolean,
- /** The amount of pixels that the user has dragged during the expansion. */
- val dragDownPxAmount: Float
+ val tracking: Boolean
)
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt
index df5ff5a..359ddd8 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt
@@ -18,13 +18,13 @@
import android.annotation.IntDef
import android.os.Trace
-import android.os.Trace.TRACE_TAG_APP as TRACE_TAG
import android.util.Log
import androidx.annotation.FloatRange
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.util.Compile
import java.util.concurrent.CopyOnWriteArrayList
import javax.inject.Inject
+import android.os.Trace.TRACE_TAG_APP as TRACE_TAG
/**
* A class responsible for managing the notification panel's current state.
@@ -42,7 +42,6 @@
@FloatRange(from = 0.0, to = 1.0) private var fraction: Float = 0f
private var expanded: Boolean = false
private var tracking: Boolean = false
- private var dragDownPxAmount: Float = 0f
/**
* Adds a listener that will be notified when the panel expansion fraction has changed and
@@ -53,7 +52,7 @@
@Deprecated("Use ShadeInteractor instead")
fun addExpansionListener(listener: ShadeExpansionListener): ShadeExpansionChangeEvent {
expansionListeners.add(listener)
- return ShadeExpansionChangeEvent(fraction, expanded, tracking, dragDownPxAmount)
+ return ShadeExpansionChangeEvent(fraction, expanded, tracking)
}
/** Adds a listener that will be notified when the panel state has changed. */
@@ -76,8 +75,7 @@
fun onPanelExpansionChanged(
@FloatRange(from = 0.0, to = 1.0) fraction: Float,
expanded: Boolean,
- tracking: Boolean,
- dragDownPxAmount: Float
+ tracking: Boolean
) {
require(!fraction.isNaN()) { "fraction cannot be NaN" }
val oldState = state
@@ -85,7 +83,6 @@
this.fraction = fraction
this.expanded = expanded
this.tracking = tracking
- this.dragDownPxAmount = dragDownPxAmount
var fullyClosed = true
var fullyOpened = false
@@ -111,7 +108,6 @@
"f=$fraction " +
"expanded=$expanded " +
"tracking=$tracking " +
- "dragDownPxAmount=$dragDownPxAmount " +
"${if (fullyOpened) " fullyOpened" else ""} " +
if (fullyClosed) " fullyClosed" else ""
)
@@ -124,8 +120,7 @@
}
}
- val expansionChangeEvent =
- ShadeExpansionChangeEvent(fraction, expanded, tracking, dragDownPxAmount)
+ val expansionChangeEvent = ShadeExpansionChangeEvent(fraction, expanded, tracking)
expansionListeners.forEach { it.onPanelExpansionChanged(expansionChangeEvent) }
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
index 2d3833c..648d4b5 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
@@ -162,9 +162,7 @@
@Binds
@SysUISingleton
- abstract fun bindsShadeViewController(
- notificationPanelViewController: NotificationPanelViewController
- ): ShadeViewController
+ abstract fun bindsShadeViewController(shadeSurface: ShadeSurface): ShadeViewController
@Binds
@SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt
index d02c215..7346a28 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt
@@ -15,7 +15,6 @@
*/
package com.android.systemui.shade
-import android.view.ViewPropertyAnimator
import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor
import com.android.systemui.shade.domain.interactor.ShadeBackActionInteractor
import com.android.systemui.shade.domain.interactor.ShadeLockscreenInteractor
@@ -48,7 +47,7 @@
fun cancelAnimation()
/** Animates the view from its current alpha to zero then runs the runnable. */
- fun fadeOut(startDelayMs: Long, durationMs: Long, endAction: Runnable): ViewPropertyAnimator
+ fun fadeOut(startDelayMs: Long, durationMs: Long, endAction: Runnable)
/** Set whether the bouncer is showing. */
fun setBouncerShowing(bouncerShowing: Boolean)
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeSurfaceImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeSurfaceImpl.kt
new file mode 100644
index 0000000..adb2928
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeSurfaceImpl.kt
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shade
+
+import com.android.systemui.statusbar.GestureRecorder
+import com.android.systemui.statusbar.phone.CentralSurfaces
+import com.android.systemui.statusbar.policy.HeadsUpManager
+import javax.inject.Inject
+
+class ShadeSurfaceImpl @Inject constructor() : ShadeSurface, ShadeViewControllerEmptyImpl() {
+ override fun initDependencies(
+ centralSurfaces: CentralSurfaces,
+ recorder: GestureRecorder,
+ hideExpandedRunnable: Runnable,
+ headsUpManager: HeadsUpManager
+ ) {}
+
+ override fun cancelPendingCollapse() {
+ // Do nothing
+ }
+
+ override fun cancelAnimation() {
+ // Do nothing
+ }
+
+ override fun fadeOut(startDelayMs: Long, durationMs: Long, endAction: Runnable) {
+ // Do nothing
+ }
+
+ override fun setBouncerShowing(bouncerShowing: Boolean) {
+ // Do nothing
+ }
+
+ override fun setTouchAndAnimationDisabled(disabled: Boolean) {
+ // TODO(b/322197941): determine if still needed
+ }
+
+ override fun setWillPlayDelayedDozeAmountAnimation(willPlay: Boolean) {
+ // TODO(b/322494538): determine if still needed
+ }
+
+ override fun setDozing(dozing: Boolean, animate: Boolean) {
+ // Do nothing
+ }
+
+ override fun setImportantForAccessibility(mode: Int) {
+ // Do nothing
+ }
+
+ override fun resetTranslation() {
+ // Do nothing
+ }
+
+ override fun resetAlpha() {
+ // Do nothing
+ }
+
+ override fun onScreenTurningOn() {
+ // Do nothing
+ }
+
+ override fun onThemeChanged() {
+ // Do nothing
+ }
+
+ override fun updateExpansionAndVisibility() {
+ // Do nothing
+ }
+
+ override fun updateResources() {
+ // Do nothing
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
index 5b2377f..4e1edd3 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
@@ -33,14 +33,12 @@
/** Returns whether the shade's top level view is enabled. */
@Deprecated("No longer supported. Do not add new calls to this.") val isViewEnabled: Boolean
- /** Returns whether status bar icons should be hidden when the shade is expanded. */
- fun shouldHideStatusBarIconsWhenExpanded(): Boolean
-
/** If the latency tracker is enabled, begins tracking expand latency. */
@Deprecated("No longer supported. Do not add new calls to this.")
fun startExpandLatencyTracking()
/** Sets the alpha value of the shade to a value between 0 and 255. */
+ @Deprecated("No longer supported. Do not add new calls to this.")
fun setAlpha(alpha: Int, animate: Boolean)
/**
@@ -48,6 +46,7 @@
*
* @see .setAlpha
*/
+ @Deprecated("No longer supported. Do not add new calls to this.")
fun setAlphaChangeAnimationEndAction(r: Runnable)
/** Sets Qs ScrimEnabled and updates QS state. */
@@ -61,7 +60,7 @@
@Deprecated("Does nothing when scene container is enabled.") fun updateSystemUiStateFlags()
/** Ensures that the touchable region is updated. */
- fun updateTouchableRegion()
+ @Deprecated("No longer supported. Do not add new calls to this.") fun updateTouchableRegion()
/**
* Sends an external (e.g. Status Bar) touch event to the Shade touch handler.
@@ -72,6 +71,8 @@
*/
fun handleExternalTouch(event: MotionEvent): Boolean
+ fun handleExternalInterceptTouch(event: MotionEvent): Boolean
+
/**
* Triggered when an input focus transfer gesture has started.
*
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt
index e037c70..0c41efd 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt
@@ -28,7 +28,7 @@
import kotlinx.coroutines.flow.flowOf
/** Empty implementation of ShadeViewController for variants with no shade. */
-class ShadeViewControllerEmptyImpl @Inject constructor() :
+open class ShadeViewControllerEmptyImpl @Inject constructor() :
ShadeViewController,
ShadeBackActionInteractor,
ShadeLockscreenInteractor,
@@ -81,6 +81,10 @@
override fun handleExternalTouch(event: MotionEvent): Boolean {
return false
}
+ override fun handleExternalInterceptTouch(event: MotionEvent): Boolean {
+ return false
+ }
+
override fun startInputFocusTransfer() {}
override fun cancelInputFocusTransfer() {}
override fun finishInputFocusTransfer(velocity: Float) {}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractor.kt
index 6611303..dfdf2ad 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractor.kt
@@ -72,4 +72,8 @@
/** Returns the StatusBarState. Note: System UI was formerly known simply as Status Bar. */
@Deprecated("Use SceneInteractor or ShadeInteractor instead") val barState: Int
+
+ /** Returns whether status bar icons should be hidden when the shade is expanded. */
+ @Deprecated("No longer supported. Do not add new calls to this.")
+ fun shouldHideStatusBarIconsWhenExpanded(): Boolean
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImpl.kt
index 561d0bc..58bcd2e 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImpl.kt
@@ -69,27 +69,21 @@
state.fromScene == Scenes.Gone ->
if (state.toScene.isExpandable()) {
// Moving from Gone to a scene that can animate-expand has a
- // panel
- // expansion
- // that tracks with the transition.
+ // panel expansion that tracks with the transition.
state.progress
} else {
// Moving from Gone to a scene that doesn't animate-expand
- // immediately makes
- // the panel fully expanded.
+ // immediately makes the panel fully expanded.
flowOf(1f)
}
state.toScene == Scenes.Gone ->
if (state.fromScene.isExpandable()) {
// Moving to Gone from a scene that can animate-expand has a
- // panel
- // expansion
- // that tracks with the transition.
+ // panel expansion that tracks with the transition.
state.progress.map { 1 - it }
} else {
// Moving to Gone from a scene that doesn't animate-expand
- // immediately makes
- // the panel fully collapsed.
+ // immediately makes the panel fully collapsed.
flowOf(0f)
}
else -> flowOf(1f)
@@ -126,6 +120,15 @@
override val barState
get() = statusBarStateController.state
+ @Deprecated("No longer supported. Do not add new calls to this.")
+ override fun shouldHideStatusBarIconsWhenExpanded(): Boolean {
+ if (shadeAnimationInteractor.isLaunchingActivity.value) {
+ return false
+ }
+ // TODO(b/325936094) if a HUN is showing, return false
+ return sceneInteractor.currentScene.value == Scenes.Lockscreen
+ }
+
private fun SceneKey.isExpandable(): Boolean {
return this == Scenes.Shade || this == Scenes.QuickSettings
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/startable/ShadeStartable.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/startable/ShadeStartable.kt
index d8216dc..f3802da 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/startable/ShadeStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/startable/ShadeStartable.kt
@@ -23,13 +23,20 @@
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.dagger.ShadeTouchLog
+import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
+import com.android.systemui.shade.ShadeExpansionStateManager
import com.android.systemui.shade.TouchLogger.Companion.logTouchesTo
import com.android.systemui.shade.data.repository.ShadeRepository
+import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor
import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.shade.transition.ScrimShadeTransitionController
import com.android.systemui.statusbar.policy.SplitShadeStateController
import javax.inject.Inject
+import javax.inject.Provider
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.launch
@@ -43,23 +50,44 @@
@ShadeTouchLog private val touchLog: LogBuffer,
private val configurationRepository: ConfigurationRepository,
private val shadeRepository: ShadeRepository,
- private val controller: SplitShadeStateController,
+ private val splitShadeStateController: SplitShadeStateController,
private val scrimShadeTransitionController: ScrimShadeTransitionController,
+ private val sceneInteractorProvider: Provider<SceneInteractor>,
+ private val panelExpansionInteractorProvider: Provider<PanelExpansionInteractor>,
+ private val shadeExpansionStateManager: ShadeExpansionStateManager,
) : CoreStartable {
override fun start() {
hydrateShadeMode()
+ hydrateShadeExpansionStateManager()
logTouchesTo(touchLog)
scrimShadeTransitionController.init()
}
+ private fun hydrateShadeExpansionStateManager() {
+ if (SceneContainerFlag.isEnabled) {
+ combine(
+ panelExpansionInteractorProvider.get().legacyPanelExpansion,
+ sceneInteractorProvider.get().isTransitionUserInputOngoing,
+ ) { panelExpansion, tracking ->
+ shadeExpansionStateManager.onPanelExpansionChanged(
+ fraction = panelExpansion,
+ expanded = panelExpansion > 0f,
+ tracking = tracking,
+ )
+ }.launchIn(applicationScope)
+ }
+ }
+
private fun hydrateShadeMode() {
applicationScope.launch {
configurationRepository.onAnyConfigurationChange
// Force initial collection.
.onStart { emit(Unit) }
.map { applicationContext.resources }
- .map { resources -> controller.shouldUseSplitNotificationShade(resources) }
+ .map { resources ->
+ splitShadeStateController.shouldUseSplitNotificationShade(resources)
+ }
.collect { isSplitShade ->
shadeRepository.setShadeMode(
if (isSplitShade) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/transition/ScrimShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/shade/transition/ScrimShadeTransitionController.kt
index 151e289..e38e53d 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/transition/ScrimShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/transition/ScrimShadeTransitionController.kt
@@ -17,28 +17,20 @@
package com.android.systemui.shade.transition
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dump.DumpManager
-import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.shade.PanelState
import com.android.systemui.shade.ShadeExpansionChangeEvent
import com.android.systemui.shade.ShadeExpansionStateManager
-import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor
import com.android.systemui.statusbar.phone.ScrimController
-import dagger.Lazy
import java.io.PrintWriter
import javax.inject.Inject
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.launch
/** Controls the scrim properties during the shade expansion transition on non-lockscreen. */
@SysUISingleton
class ScrimShadeTransitionController
@Inject
constructor(
- @Application private val applicationScope: CoroutineScope,
private val shadeExpansionStateManager: ShadeExpansionStateManager,
- private val panelExpansionInteractor: Lazy<PanelExpansionInteractor>,
private val dumpManager: DumpManager,
private val scrimController: ScrimController,
) {
@@ -47,32 +39,17 @@
private var currentPanelState: Int? = null
fun init() {
- if (SceneContainerFlag.isEnabled) {
- applicationScope.launch {
- panelExpansionInteractor.get().legacyPanelExpansion.collect { panelExpansion ->
- onPanelExpansionChanged(
- ShadeExpansionChangeEvent(
- fraction = panelExpansion,
- expanded = panelExpansion > 0f,
- tracking = true,
- dragDownPxAmount = 0f,
- )
- )
- }
- }
- } else {
- val currentState =
- shadeExpansionStateManager.addExpansionListener(this::onPanelExpansionChanged)
- onPanelExpansionChanged(currentState)
- shadeExpansionStateManager.addStateListener(this::onPanelStateChanged)
- }
+ val currentState =
+ shadeExpansionStateManager.addExpansionListener(this::onPanelExpansionChanged)
+ onPanelExpansionChanged(currentState)
+ shadeExpansionStateManager.addStateListener(this::onPanelStateChanged)
dumpManager.registerDumpable(
ScrimShadeTransitionController::class.java.simpleName,
this::dump
)
}
- fun onPanelStateChanged(@PanelState state: Int) {
+ private fun onPanelStateChanged(@PanelState state: Int) {
currentPanelState = state
onStateChanged()
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java b/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java
index 8d7fc98..acb5339 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java
@@ -19,8 +19,6 @@
import android.util.AttributeSet;
import android.widget.TextView;
-import com.android.settingslib.WirelessUtils;
-
/** Shows the operator name */
public class OperatorNameView extends TextView {
private boolean mDemoMode;
@@ -41,13 +39,14 @@
mDemoMode = demoMode;
}
- void update(boolean showOperatorName,
+ void update(
+ boolean showOperatorName,
boolean hasMobile,
+ boolean airplaneMode,
OperatorNameViewController.SubInfo sub
) {
setVisibility(showOperatorName ? VISIBLE : GONE);
- boolean airplaneMode = WirelessUtils.isAirplaneModeOn(mContext);
if (!hasMobile || airplaneMode) {
setText(null);
setVisibility(GONE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameViewController.java
index 8afc72f..6e7d8f4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameViewController.java
@@ -16,11 +16,9 @@
package com.android.systemui.statusbar;
-import android.annotation.NonNull;
import android.os.Bundle;
import android.telephony.ServiceState;
import android.telephony.SubscriptionInfo;
-import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.view.View;
@@ -28,47 +26,60 @@
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.demomode.DemoModeCommandReceiver;
import com.android.systemui.plugins.DarkIconDispatcher;
-import com.android.systemui.statusbar.connectivity.IconState;
-import com.android.systemui.statusbar.connectivity.NetworkController;
-import com.android.systemui.statusbar.connectivity.SignalCallback;
import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment;
+import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor;
+import com.android.systemui.statusbar.pipeline.mobile.util.SubscriptionManagerProxy;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.util.CarrierConfigTracker;
import com.android.systemui.util.ViewController;
+import com.android.systemui.util.kotlin.JavaAdapter;
import javax.inject.Inject;
+import kotlinx.coroutines.Job;
+
/** Controller for {@link OperatorNameView}. */
public class OperatorNameViewController extends ViewController<OperatorNameView> {
private static final String KEY_SHOW_OPERATOR_NAME = "show_operator_name";
private final DarkIconDispatcher mDarkIconDispatcher;
- private final NetworkController mNetworkController;
private final TunerService mTunerService;
private final TelephonyManager mTelephonyManager;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final CarrierConfigTracker mCarrierConfigTracker;
+ private final AirplaneModeInteractor mAirplaneModeInteractor;
+ private final SubscriptionManagerProxy mSubscriptionManagerProxy;
+ private final JavaAdapter mJavaAdapter;
+
+ private Job mAirplaneModeJob;
private OperatorNameViewController(OperatorNameView view,
DarkIconDispatcher darkIconDispatcher,
- NetworkController networkController,
TunerService tunerService,
TelephonyManager telephonyManager,
KeyguardUpdateMonitor keyguardUpdateMonitor,
- CarrierConfigTracker carrierConfigTracker) {
+ CarrierConfigTracker carrierConfigTracker,
+ AirplaneModeInteractor airplaneModeInteractor,
+ SubscriptionManagerProxy subscriptionManagerProxy,
+ JavaAdapter javaAdapter) {
super(view);
mDarkIconDispatcher = darkIconDispatcher;
- mNetworkController = networkController;
mTunerService = tunerService;
mTelephonyManager = telephonyManager;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mCarrierConfigTracker = carrierConfigTracker;
+ mAirplaneModeInteractor = airplaneModeInteractor;
+ mSubscriptionManagerProxy = subscriptionManagerProxy;
+ mJavaAdapter = javaAdapter;
}
@Override
protected void onViewAttached() {
mDarkIconDispatcher.addDarkReceiver(mDarkReceiver);
- mNetworkController.addCallback(mSignalCallback);
+ mAirplaneModeJob =
+ mJavaAdapter.alwaysCollectFlow(
+ mAirplaneModeInteractor.isAirplaneMode(),
+ (isAirplaneMode) -> update());
mTunerService.addTunable(mTunable, KEY_SHOW_OPERATOR_NAME);
mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
}
@@ -76,7 +87,7 @@
@Override
protected void onViewDetached() {
mDarkIconDispatcher.removeDarkReceiver(mDarkReceiver);
- mNetworkController.removeCallback(mSignalCallback);
+ mAirplaneModeJob.cancel(null);
mTunerService.removeTunable(mTunable);
mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateMonitorCallback);
}
@@ -87,11 +98,17 @@
mCarrierConfigTracker
.getShowOperatorNameInStatusBarConfig(defaultSubInfo.getSubId())
&& (mTunerService.getValue(KEY_SHOW_OPERATOR_NAME, 1) != 0);
- mView.update(showOperatorName, mTelephonyManager.isDataCapable(), getDefaultSubInfo());
+ mView.update(
+ showOperatorName,
+ mTelephonyManager.isDataCapable(),
+ mAirplaneModeInteractor.isAirplaneMode().getValue(),
+ getDefaultSubInfo()
+ );
}
private SubInfo getDefaultSubInfo() {
- int defaultSubId = SubscriptionManager.getDefaultDataSubscriptionId();
+ int defaultSubId = mSubscriptionManagerProxy.getDefaultDataSubscriptionId();
+
SubscriptionInfo sI = mKeyguardUpdateMonitor.getSubscriptionInfoForSubId(defaultSubId);
return new SubInfo(
sI.getSubscriptionId(),
@@ -103,36 +120,44 @@
/** Factory for constructing an {@link OperatorNameViewController}. */
public static class Factory {
private final DarkIconDispatcher mDarkIconDispatcher;
- private final NetworkController mNetworkController;
private final TunerService mTunerService;
private final TelephonyManager mTelephonyManager;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final CarrierConfigTracker mCarrierConfigTracker;
+ private final AirplaneModeInteractor mAirplaneModeInteractor;
+ private final SubscriptionManagerProxy mSubscriptionManagerProxy;
+ private final JavaAdapter mJavaAdapter;
@Inject
public Factory(DarkIconDispatcher darkIconDispatcher,
- NetworkController networkController,
TunerService tunerService,
TelephonyManager telephonyManager,
KeyguardUpdateMonitor keyguardUpdateMonitor,
- CarrierConfigTracker carrierConfigTracker) {
+ CarrierConfigTracker carrierConfigTracker,
+ AirplaneModeInteractor airplaneModeInteractor,
+ SubscriptionManagerProxy subscriptionManagerProxy,
+ JavaAdapter javaAdapter) {
mDarkIconDispatcher = darkIconDispatcher;
- mNetworkController = networkController;
mTunerService = tunerService;
mTelephonyManager = telephonyManager;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mCarrierConfigTracker = carrierConfigTracker;
+ mAirplaneModeInteractor = airplaneModeInteractor;
+ mSubscriptionManagerProxy = subscriptionManagerProxy;
+ mJavaAdapter = javaAdapter;
}
/** Create an {@link OperatorNameViewController}. */
public OperatorNameViewController create(OperatorNameView view) {
return new OperatorNameViewController(view,
mDarkIconDispatcher,
- mNetworkController,
mTunerService,
mTelephonyManager,
mKeyguardUpdateMonitor,
- mCarrierConfigTracker);
+ mCarrierConfigTracker,
+ mAirplaneModeInteractor,
+ mSubscriptionManagerProxy,
+ mJavaAdapter);
}
}
@@ -149,13 +174,6 @@
(area, darkIntensity, tint) ->
mView.setTextColor(DarkIconDispatcher.getTint(area, mView, tint));
- private final SignalCallback mSignalCallback = new SignalCallback() {
- @Override
- public void setIsAirplaneMode(@NonNull IconState icon) {
- update();
- }
- };
-
private final TunerService.Tunable mTunable = (key, newValue) -> update();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
index f960fca..e5b6497 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
@@ -35,9 +35,11 @@
import com.android.systemui.dump.DumpManager;
import com.android.systemui.media.controls.domain.pipeline.MediaDataManager;
import com.android.systemui.power.domain.interactor.PowerInteractor;
+import com.android.systemui.scene.shared.flag.SceneContainerFlags;
import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.shade.NotificationPanelViewController;
import com.android.systemui.shade.ShadeSurface;
+import com.android.systemui.shade.ShadeSurfaceImpl;
import com.android.systemui.shade.carrier.ShadeCarrierGroupController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationClickNotifier;
@@ -59,6 +61,8 @@
import com.android.systemui.statusbar.phone.StatusBarRemoteInputCallback;
import com.android.systemui.statusbar.policy.KeyguardStateController;
+import javax.inject.Provider;
+
import dagger.Binds;
import dagger.Lazy;
import dagger.Module;
@@ -178,9 +182,20 @@
* The {@link com.android.systemui.shade.ShadeViewController} interface is bound in
* {@link com.android.systemui.shade.ShadeModule} so others can access it.
*/
- @Binds
+ @Provides
@SysUISingleton
- ShadeSurface provideShadeSurface(NotificationPanelViewController impl);
+ static ShadeSurface provideShadeSurface(
+ SceneContainerFlags sceneContainerFlags,
+ Provider<ShadeSurfaceImpl> sceneContainerOn,
+ Provider<NotificationPanelViewController> sceneContainerOff) {
+ if (sceneContainerFlags.isEnabled()) {
+ return sceneContainerOn.get();
+ } else {
+ return sceneContainerOff.get();
+ }
+
+ }
+
/** */
@Binds
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
index 7c71864..4c66f66 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
@@ -23,7 +23,9 @@
import com.android.app.animation.Interpolators
import com.android.app.animation.InterpolatorsAndroidX
import com.android.systemui.Dumpable
+import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.shade.ShadeExpansionChangeEvent
@@ -47,11 +49,14 @@
import javax.inject.Inject
import kotlin.math.max
import kotlin.math.min
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
@SysUISingleton
class NotificationWakeUpCoordinator
@Inject
constructor(
+ @Application applicationScope: CoroutineScope,
dumpManager: DumpManager,
private val mHeadsUpManager: HeadsUpManager,
private val statusBarStateController: StatusBarStateController,
@@ -60,6 +65,7 @@
private val screenOffAnimationController: ScreenOffAnimationController,
private val logger: NotificationWakeUpCoordinatorLogger,
private val notifsKeyguardInteractor: NotificationsKeyguardInteractor,
+ private val communalInteractor: CommunalInteractor,
) :
OnHeadsUpChangedListener,
StatusBarStateController.StateListener,
@@ -201,6 +207,13 @@
}
}
)
+ applicationScope.launch {
+ communalInteractor.isIdleOnCommunal.collect {
+ if (!overrideDozeAmountIfCommunalShowing()) {
+ maybeClearHardDozeAmountOverrideHidingNotifs()
+ }
+ }
+ }
}
fun setStackScroller(stackScrollerController: NotificationStackScrollLayoutController) {
@@ -302,6 +315,10 @@
return
}
+ if (overrideDozeAmountIfCommunalShowing()) {
+ return
+ }
+
if (clearHardDozeAmountOverride()) {
return
}
@@ -311,9 +328,12 @@
private fun setHardDozeAmountOverride(dozing: Boolean, source: String) {
logger.logSetDozeAmountOverride(dozing = dozing, source = source)
+ val previousOverride = hardDozeAmountOverride
hardDozeAmountOverride = if (dozing) 1f else 0f
hardDozeAmountOverrideSource = source
- updateDozeAmount()
+ if (previousOverride != hardDozeAmountOverride) {
+ updateDozeAmount()
+ }
}
private fun clearHardDozeAmountOverride(): Boolean {
@@ -434,6 +454,11 @@
return
}
+ if (overrideDozeAmountIfCommunalShowing()) {
+ this.state = newState
+ return
+ }
+
maybeClearHardDozeAmountOverrideHidingNotifs()
this.state = newState
@@ -471,6 +496,18 @@
return false
}
+ private fun overrideDozeAmountIfCommunalShowing(): Boolean {
+ if (communalInteractor.isIdleOnCommunal.value) {
+ if (statusBarStateController.state == StatusBarState.KEYGUARD) {
+ setHardDozeAmountOverride(dozing = true, source = "Override: communal (keyguard)")
+ } else {
+ setHardDozeAmountOverride(dozing = false, source = "Override: communal (shade)")
+ }
+ return true
+ }
+ return false
+ }
+
/**
* If the last [setDozeAmount] call was an override to hide notifications, then this call will
* check for the set of states that may have caused that override, and if none of them still
@@ -483,20 +520,23 @@
val onKeyguard = statusBarStateController.state == StatusBarState.KEYGUARD
val dozing = statusBarStateController.isDozing
val bypass = bypassController.bypassEnabled
+ val idleOnCommunal = communalInteractor.isIdleOnCommunal.value
val animating =
screenOffAnimationController.overrideNotificationsFullyDozingOnKeyguard()
- // Overrides are set by [overrideDozeAmountIfAnimatingScreenOff] and
- // [overrideDozeAmountIfBypass] based on 'animating' and 'bypass' respectively, so only
- // clear the override if both those conditions are cleared. But also require either
+ // Overrides are set by [overrideDozeAmountIfAnimatingScreenOff],
+ // [overrideDozeAmountIfBypass] and [overrideDozeAmountIfCommunalShowing] based on
+ // 'animating', 'bypass' and 'idleOnCommunal' respectively, so only clear the override
+ // if all of those conditions are cleared. But also require either
// !dozing or !onKeyguard because those conditions should indicate that we intend
// notifications to be visible, and thus it is safe to unhide them.
- val willRemove = (!onKeyguard || !dozing) && !bypass && !animating
+ val willRemove = (!onKeyguard || !dozing) && !bypass && !animating && !idleOnCommunal
logger.logMaybeClearHardDozeAmountOverrideHidingNotifs(
willRemove = willRemove,
onKeyguard = onKeyguard,
dozing = dozing,
bypass = bypass,
animating = animating,
+ idleOnCommunal = idleOnCommunal,
)
if (willRemove) {
clearHardDozeAmountOverride()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt
index 502e1d9..9619bea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt
@@ -95,6 +95,7 @@
onKeyguard: Boolean,
dozing: Boolean,
bypass: Boolean,
+ idleOnCommunal: Boolean,
animating: Boolean,
) {
buffer.log(
@@ -103,7 +104,7 @@
{
str1 =
"willRemove=$willRemove onKeyguard=$onKeyguard dozing=$dozing" +
- " bypass=$bypass animating=$animating"
+ " bypass=$bypass animating=$animating idleOnCommunal=$idleOnCommunal"
},
{ "maybeClearHardDozeAmountOverrideHidingNotifs() $str1" }
)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index b6f653f..2798dbf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -164,6 +164,7 @@
import com.android.systemui.qs.QSPanelController;
import com.android.systemui.res.R;
import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor;
+import com.android.systemui.scene.shared.flag.SceneContainerFlag;
import com.android.systemui.scene.shared.flag.SceneContainerFlags;
import com.android.systemui.scrim.ScrimView;
import com.android.systemui.settings.UserTracker;
@@ -1256,11 +1257,13 @@
mScreenOffAnimationController.initialize(this, mShadeSurface, mLightRevealScrim);
updateLightRevealScrimVisibility();
- mShadeSurface.initDependencies(
- this,
- mGestureRec,
- mShadeController::makeExpandedInvisible,
- mHeadsUpManager);
+ if (!SceneContainerFlag.isEnabled()) {
+ mShadeSurface.initDependencies(
+ this,
+ mGestureRec,
+ mShadeController::makeExpandedInvisible,
+ mHeadsUpManager);
+ }
// Set up the quick settings tile panel
final View container = getNotificationShadeWindowView().findViewById(R.id.qs_frame);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.kt
index 82b10bc..eadb7f5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.kt
@@ -23,12 +23,12 @@
import android.widget.FrameLayout
import androidx.annotation.StringRes
import com.android.keyguard.LockIconViewController
-import com.android.systemui.res.R
import com.android.systemui.keyguard.ui.binder.KeyguardBottomAreaViewBinder
import com.android.systemui.keyguard.ui.binder.KeyguardBottomAreaViewBinder.bind
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.res.R
import com.android.systemui.statusbar.VibratorHelper
/**
@@ -155,13 +155,13 @@
// make top of ambient indication view the bottom of the lock icon
it.layout(
ambientLeft,
- lockIconViewController?.bottom?.toInt() ?: 0,
+ lockIconViewController?.getBottom()?.toInt() ?: 0,
right - ambientLeft,
ambientTop + it.measuredHeight
)
} else {
// make bottom of ambient indication view the top of the lock icon
- val lockLocationTop = lockIconViewController?.top ?: 0
+ val lockLocationTop = lockIconViewController?.getTop() ?: 0
it.layout(
ambientLeft,
lockLocationTop.toInt() - it.measuredHeight,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index febe5a2..afd2415 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -579,7 +579,7 @@
ViewRootImpl viewRoot = getViewRootImpl();
if (viewRoot != null) {
viewRoot.getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
- OnBackInvokedDispatcher.PRIORITY_OVERLAY, mOnBackInvokedCallback);
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT, mOnBackInvokedCallback);
mIsBackCallbackRegistered = true;
} else {
if (DEBUG) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
index 617e107..c52132f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
@@ -46,7 +46,7 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.res.R;
import com.android.systemui.shade.ShadeExpansionStateManager;
-import com.android.systemui.shade.ShadeViewController;
+import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.OperatorNameView;
import com.android.systemui.statusbar.OperatorNameViewController;
@@ -79,6 +79,8 @@
import com.android.systemui.util.CarrierConfigTracker.DefaultDataSubscriptionChangedListener;
import com.android.systemui.util.settings.SecureSettings;
+import kotlin.Unit;
+
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
@@ -89,8 +91,6 @@
import javax.inject.Inject;
-import kotlin.Unit;
-
import kotlinx.coroutines.DisposableHandle;
/**
@@ -115,7 +115,7 @@
private PhoneStatusBarView mStatusBar;
private final StatusBarStateController mStatusBarStateController;
private final KeyguardStateController mKeyguardStateController;
- private final ShadeViewController mShadeViewController;
+ private final PanelExpansionInteractor mPanelExpansionInteractor;
private MultiSourceMinAlphaController mEndSideAlphaController;
private LinearLayout mEndSideContent;
private View mClockView;
@@ -227,7 +227,7 @@
CollapsedStatusBarViewBinder collapsedStatusBarViewBinder,
StatusBarHideIconsForBouncerManager statusBarHideIconsForBouncerManager,
KeyguardStateController keyguardStateController,
- ShadeViewController shadeViewController,
+ PanelExpansionInteractor panelExpansionInteractor,
StatusBarStateController statusBarStateController,
NotificationIconContainerStatusBarViewBinder nicViewBinder,
CommandQueue commandQueue,
@@ -252,7 +252,7 @@
mStatusBarHideIconsForBouncerManager = statusBarHideIconsForBouncerManager;
mDarkIconManagerFactory = darkIconManagerFactory;
mKeyguardStateController = keyguardStateController;
- mShadeViewController = shadeViewController;
+ mPanelExpansionInteractor = panelExpansionInteractor;
mStatusBarStateController = statusBarStateController;
mNicViewBinder = nicViewBinder;
mCommandQueue = commandQueue;
@@ -603,7 +603,7 @@
private boolean shouldHideStatusBar() {
if (!mShadeExpansionStateManager.isClosed()
- && mShadeViewController.shouldHideStatusBarIconsWhenExpanded()) {
+ && mPanelExpansionInteractor.shouldHideStatusBarIconsWhenExpanded()) {
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/domain/interactor/AirplaneModeInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/domain/interactor/AirplaneModeInteractor.kt
index c6c8823..684e38e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/domain/interactor/AirplaneModeInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/domain/interactor/AirplaneModeInteractor.kt
@@ -23,6 +23,7 @@
import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.map
/**
@@ -40,7 +41,7 @@
private val mobileConnectionsRepository: MobileConnectionsRepository,
) {
/** True if the device is currently in airplane mode. */
- val isAirplaneMode: Flow<Boolean> = airplaneModeRepository.isAirplaneMode
+ val isAirplaneMode: StateFlow<Boolean> = airplaneModeRepository.isAirplaneMode
/** True if we're configured to force-hide the airplane mode icon and false otherwise. */
val isForceHidden: Flow<Boolean> =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java
index 068e0a6..860068c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java
@@ -94,7 +94,8 @@
int packageUid;
try {
- packageUid = mPackageManager.getPackageUid(info.getPackageName(), 0);
+ packageUid = mPackageManager.getPackageUidAsUser(info.getPackageName(),
+ info.getUserHandle().getIdentifier());
} catch (PackageManager.NameNotFoundException e) {
Log.w(LOG_TAG, "Package " + info.getPackageName() + " not found");
packageUid = -1;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModel.kt
index 0207d6e..04d7b1f 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModel.kt
@@ -36,10 +36,15 @@
}
fun onSettingsClicked() {
- activityStarter.startActivity(
- Intent(Settings.ACTION_SOUND_SETTINGS)
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_REORDER_TO_FRONT),
- true,
- ) { volumePanelViewModel.dismissPanel() }
+ activityStarter.startActivityDismissingKeyguard(
+ /* intent = */ Intent(Settings.ACTION_SOUND_SETTINGS),
+ /* onlyProvisioned = */ false,
+ /* dismissShade = */ true,
+ /* disallowEnterPictureInPictureWhileLaunching = */ false,
+ /* callback = */ { volumePanelViewModel.dismissPanel() },
+ /* flags = */ Intent.FLAG_ACTIVITY_REORDER_TO_FRONT,
+ /* animationController = */ null,
+ /* userHandle = */ null,
+ )
}
}
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 1d9b90a..ff18418 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java
@@ -91,17 +91,22 @@
@Background Executor bgExecutor,
SecureSettings secureSettings,
QuickAccessWalletClient quickAccessWalletClient,
- SystemClock clock) {
+ SystemClock clock,
+ RoleManager roleManager) {
mContext = context;
mExecutor = executor;
mBgExecutor = bgExecutor;
mSecureSettings = secureSettings;
- mRoleManager = mContext.getSystemService(RoleManager.class);
+ mRoleManager = roleManager;
mQuickAccessWalletClient = quickAccessWalletClient;
mClock = clock;
mQawClientCreatedTimeMillis = mClock.elapsedRealtime();
}
+ public boolean isWalletRoleAvailable() {
+ return mRoleManager.isRoleAvailable(RoleManager.ROLE_WALLET);
+ }
+
/**
* Returns true if the Quick Access Wallet service & feature is available.
*/
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/keyguard/LegacyLockIconViewControllerBaseTest.java
similarity index 98%
rename from packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
rename to packages/SystemUI/tests/src/com/android/keyguard/LegacyLockIconViewControllerBaseTest.java
index 1c77351..f924ab4 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/LegacyLockIconViewControllerBaseTest.java
@@ -68,7 +68,7 @@
import org.mockito.MockitoSession;
import org.mockito.quality.Strictness;
-public class LockIconViewControllerBaseTest extends SysuiTestCase {
+public class LegacyLockIconViewControllerBaseTest extends SysuiTestCase {
protected static final String UNLOCKED_LABEL = "unlocked";
protected static final String LOCKED_LABEL = "locked";
protected static final int PADDING = 10;
@@ -98,7 +98,7 @@
protected @Mock PrimaryBouncerInteractor mPrimaryBouncerInteractor;
- protected LockIconViewController mUnderTest;
+ protected LegacyLockIconViewController mUnderTest;
// Capture listeners so that they can be used to send events
@Captor protected ArgumentCaptor<View.OnAttachStateChangeListener> mAttachCaptor =
@@ -153,7 +153,7 @@
mFeatureFlags.set(LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false);
mFeatureFlags.set(LOCKSCREEN_ENABLE_LANDSCAPE, false);
- mUnderTest = new LockIconViewController(
+ mUnderTest = new LegacyLockIconViewController(
mStatusBarStateController,
mKeyguardUpdateMonitor,
mKeyguardViewController,
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/LegacyLockIconViewControllerTest.java
similarity index 99%
rename from packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java
rename to packages/SystemUI/tests/src/com/android/keyguard/LegacyLockIconViewControllerTest.java
index b0887ef..8689842 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/LegacyLockIconViewControllerTest.java
@@ -51,7 +51,7 @@
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
-public class LockIconViewControllerTest extends LockIconViewControllerBaseTest {
+public class LegacyLockIconViewControllerTest extends LegacyLockIconViewControllerBaseTest {
@Override
public void setUp() throws Exception {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/LegacyLockIconViewControllerWithCoroutinesTest.kt
similarity index 98%
rename from packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerWithCoroutinesTest.kt
rename to packages/SystemUI/tests/src/com/android/keyguard/LegacyLockIconViewControllerWithCoroutinesTest.kt
index 1213518..25a87b8 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerWithCoroutinesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/LegacyLockIconViewControllerWithCoroutinesTest.kt
@@ -39,7 +39,7 @@
@RunWith(AndroidTestingRunner::class)
@SmallTest
-class LockIconViewControllerWithCoroutinesTest : LockIconViewControllerBaseTest() {
+class LegacyLockIconViewControllerWithCoroutinesTest : LegacyLockIconViewControllerBaseTest() {
/** After migration, replaces LockIconViewControllerTest version */
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
index de696f4..71f6081 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
@@ -165,7 +165,7 @@
mMenuView = spy(
new MenuView(mSpyContext, mMenuViewModel, menuViewAppearance, mSecureSettings));
// Ensure tests don't actually update metrics.
- doNothing().when(mMenuView).incrementTexMetric(any(), anyInt());
+ doNothing().when(mMenuView).incrementTexMetric(any());
mMenuViewLayer = spy(new MenuViewLayer(mSpyContext, mStubWindowManager,
mStubAccessibilityManager, mMenuViewModel, menuViewAppearance, mMenuView,
@@ -414,33 +414,25 @@
@Test
@EnableFlags(Flags.FLAG_FLOATING_MENU_DRAG_TO_EDIT)
public void onDismissAction_incrementsTexMetricDismiss() {
- int uid1 = 1234, uid2 = 5678;
mMenuViewModel.onTargetFeaturesChanged(
- List.of(new TestAccessibilityTarget(mSpyContext, uid1),
- new TestAccessibilityTarget(mSpyContext, uid2)));
+ List.of(new TestAccessibilityTarget(mSpyContext, 1234),
+ new TestAccessibilityTarget(mSpyContext, 5678)));
mMenuViewLayer.dispatchAccessibilityAction(R.id.action_remove_menu);
- ArgumentCaptor<Integer> uidCaptor = ArgumentCaptor.forClass(Integer.class);
- verify(mMenuView, times(2)).incrementTexMetric(eq(MenuViewLayer.TEX_METRIC_DISMISS),
- uidCaptor.capture());
- assertThat(uidCaptor.getAllValues()).containsExactly(uid1, uid2);
+ verify(mMenuView, times(1)).incrementTexMetric(eq(MenuViewLayer.TEX_METRIC_DISMISS));
}
@Test
@EnableFlags(Flags.FLAG_FLOATING_MENU_DRAG_TO_EDIT)
public void onEditAction_incrementsTexMetricEdit() {
- int uid1 = 1234, uid2 = 5678;
mMenuViewModel.onTargetFeaturesChanged(
- List.of(new TestAccessibilityTarget(mSpyContext, uid1),
- new TestAccessibilityTarget(mSpyContext, uid2)));
+ List.of(new TestAccessibilityTarget(mSpyContext, 1234),
+ new TestAccessibilityTarget(mSpyContext, 5678)));
mMenuViewLayer.dispatchAccessibilityAction(R.id.action_edit);
- ArgumentCaptor<Integer> uidCaptor = ArgumentCaptor.forClass(Integer.class);
- verify(mMenuView, times(2)).incrementTexMetric(eq(MenuViewLayer.TEX_METRIC_EDIT),
- uidCaptor.capture());
- assertThat(uidCaptor.getAllValues()).containsExactly(uid1, uid2);
+ verify(mMenuView, times(1)).incrementTexMetric(eq(MenuViewLayer.TEX_METRIC_EDIT));
}
/** Simplified AccessibilityTarget for testing MenuViewLayer. */
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java
new file mode 100644
index 0000000..38e3171
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility.hearingaid;
+
+import static com.android.systemui.statusbar.phone.SystemUIDialog.DEFAULT_DISMISS_ON_DEVICE_LOCK;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.animation.DialogTransitionAnimator;
+import com.android.systemui.model.SysUiState;
+import com.android.systemui.statusbar.phone.SystemUIDialog;
+import com.android.systemui.statusbar.phone.SystemUIDialogManager;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+/** Tests for {@link HearingDevicesDialogDelegate}. */
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@SmallTest
+public class HearingDevicesDialogDelegateTest extends SysuiTestCase {
+ @Rule
+ public MockitoRule mockito = MockitoJUnit.rule();
+
+ @Mock
+ private SystemUIDialog.Factory mSystemUIDialogFactory;
+ @Mock
+ private SystemUIDialogManager mSystemUIDialogManager;
+ @Mock
+ private SysUiState mSysUiState;
+ @Mock
+ private DialogTransitionAnimator mDialogTransitionAnimator;
+ private SystemUIDialog mDialog;
+ private HearingDevicesDialogDelegate mDialogDelegate;
+
+ @Before
+ public void setUp() {
+ mDialogDelegate = new HearingDevicesDialogDelegate(mSystemUIDialogFactory);
+ mDialog = new SystemUIDialog(
+ mContext,
+ 0,
+ DEFAULT_DISMISS_ON_DEVICE_LOCK,
+ mSystemUIDialogManager,
+ mSysUiState,
+ getFakeBroadcastDispatcher(),
+ mDialogTransitionAnimator,
+ mDialogDelegate
+ );
+
+ when(mSystemUIDialogFactory.create(any(SystemUIDialog.Delegate.class)))
+ .thenReturn(mDialog);
+ }
+
+ @Test
+ public void createDialog_dialogShown() {
+ assertThat(mDialogDelegate.createDialog()).isEqualTo(mDialog);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt
index 58273d6..4f2b690 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt
@@ -22,7 +22,7 @@
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
import androidx.test.filters.SmallTest
-import com.android.keyguard.LockIconViewController
+import com.android.keyguard.LegacyLockIconViewController
import com.android.systemui.Flags as AConfigFlags
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.AuthController
@@ -58,7 +58,7 @@
@Mock(answer = Answers.RETURNS_DEEP_STUBS) private lateinit var windowManager: WindowManager
@Mock private lateinit var notificationPanelView: NotificationPanelView
private lateinit var featureFlags: FakeFeatureFlags
- @Mock private lateinit var lockIconViewController: LockIconViewController
+ @Mock private lateinit var lockIconViewController: LegacyLockIconViewController
@Mock private lateinit var falsingManager: FalsingManager
@Mock private lateinit var deviceEntryIconViewModel: DeviceEntryIconViewModel
private lateinit var underTest: DefaultDeviceEntrySection
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/panels/domain/repository/IconTilesRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/domain/repository/IconTilesRepositoryImplTest.kt
new file mode 100644
index 0000000..8cc3a85
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/domain/repository/IconTilesRepositoryImplTest.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.panels.domain.repository
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.qs.panels.data.repository.IconTilesRepositoryImpl
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class IconTilesRepositoryImplTest : SysuiTestCase() {
+
+ private val underTest = IconTilesRepositoryImpl()
+
+ @Test
+ fun iconTilesSpecsIsValid() = runTest {
+ val tilesSpecs by collectLastValue(underTest.iconTilesSpecs)
+ assertThat(tilesSpecs).isEqualTo(ICON_ONLY_TILES_SPECS)
+ }
+
+ companion object {
+ private val ICON_ONLY_TILES_SPECS =
+ setOf(
+ TileSpec.create("airplane"),
+ TileSpec.create("battery"),
+ TileSpec.create("cameratoggle"),
+ TileSpec.create("cast"),
+ TileSpec.create("color_correction"),
+ TileSpec.create("inversion"),
+ TileSpec.create("saver"),
+ TileSpec.create("dnd"),
+ TileSpec.create("flashlight"),
+ TileSpec.create("location"),
+ TileSpec.create("mictoggle"),
+ TileSpec.create("nfc"),
+ TileSpec.create("night"),
+ TileSpec.create("rotation")
+ )
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/HearingDevicesTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/HearingDevicesTileTest.java
index 326df5c..73aa54c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/HearingDevicesTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/HearingDevicesTileTest.java
@@ -21,6 +21,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.content.Intent;
import android.os.Handler;
@@ -29,12 +30,14 @@
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.view.View;
import androidx.test.filters.SmallTest;
import com.android.internal.logging.MetricsLogger;
import com.android.systemui.Flags;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.accessibility.hearingaid.HearingDevicesDialogManager;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -73,6 +76,8 @@
private ActivityStarter mActivityStarter;
@Mock
private QSLogger mQSLogger;
+ @Mock
+ HearingDevicesDialogManager mHearingDevicesDialogManager;
private TestableLooper mTestableLooper;
private HearingDevicesTile mTile;
@@ -80,6 +85,7 @@
@Before
public void setUp() throws Exception {
mTestableLooper = TestableLooper.get(this);
+ when(mHost.getContext()).thenReturn(mContext);
mTile = new HearingDevicesTile(
mHost,
@@ -90,7 +96,8 @@
mMetricsLogger,
mStatusBarStateController,
mActivityStarter,
- mQSLogger);
+ mQSLogger,
+ mHearingDevicesDialogManager);
mTile.initialize();
mTestableLooper.processAllMessages();
@@ -125,4 +132,13 @@
assertThat(IntentCaptor.getValue().getAction()).isEqualTo(
Settings.ACTION_HEARING_DEVICES_SETTINGS);
}
+
+ @Test
+ public void handleClick_dialogShown() {
+ View view = new View(mContext);
+ mTile.handleClick(view);
+ mTestableLooper.processAllMessages();
+
+ verify(mHearingDevicesDialogManager).showDialog(view);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java
index 2d18f92..122d9e4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java
@@ -58,7 +58,6 @@
import androidx.test.filters.SmallTest;
import com.android.internal.logging.MetricsLogger;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.plugins.ActivityStarter;
@@ -68,6 +67,7 @@
import com.android.systemui.qs.QsEventLogger;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.res.R;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.settings.SecureSettings;
import com.android.systemui.wallet.controller.QuickAccessWalletController;
@@ -198,7 +198,8 @@
}
@Test
- public void testIsAvailable_qawFeatureAvailable() {
+ public void testIsAvailable_qawFeatureAvailableWalletUnavailable() {
+ when(mController.isWalletRoleAvailable()).thenReturn(false);
when(mPackageManager.hasSystemFeature(FEATURE_NFC_HOST_CARD_EMULATION)).thenReturn(true);
when(mPackageManager.hasSystemFeature("org.chromium.arc")).thenReturn(false);
when(mSecureSettings.getStringForUser(NFC_PAYMENT_DEFAULT_COMPONENT,
@@ -208,6 +209,16 @@
}
@Test
+ public void testIsAvailable_nfcUnavailableWalletAvailable() {
+ when(mController.isWalletRoleAvailable()).thenReturn(true);
+ when(mHost.getUserId()).thenReturn(PRIMARY_USER_ID);
+ when(mPackageManager.hasSystemFeature(FEATURE_NFC_HOST_CARD_EMULATION)).thenReturn(false);
+ when(mPackageManager.hasSystemFeature("org.chromium.arc")).thenReturn(false);
+
+ assertTrue(mTile.isAvailable());
+ }
+
+ @Test
public void testHandleClick_startQuickAccessUiIntent_noCard() {
setUpWalletCard(/* hasCard= */ false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegateTest.kt
index 6e48074..598a0f2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegateTest.kt
@@ -39,7 +39,6 @@
import com.android.systemui.settings.UserContextProvider
import com.android.systemui.statusbar.phone.SystemUIDialog
import com.android.systemui.statusbar.phone.SystemUIDialogManager
-import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
@@ -50,6 +49,7 @@
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.eq
+import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
@@ -59,7 +59,6 @@
@TestableLooper.RunWithLooper(setAsMainLooper = true)
class ScreenRecordPermissionDialogDelegateTest : SysuiTestCase() {
- //@Mock private lateinit var dialogFactory: SystemUIDialog.Factory
@Mock private lateinit var starter: ActivityStarter
@Mock private lateinit var controller: RecordingController
@Mock private lateinit var userContextProvider: UserContextProvider
@@ -76,13 +75,13 @@
whenever(flags.isEnabled(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING)).thenReturn(true)
val systemUIDialogFactory =
- SystemUIDialog.Factory(
- context,
- Dependency.get(SystemUIDialogManager::class.java),
- Dependency.get(SysUiState::class.java),
- Dependency.get(BroadcastDispatcher::class.java),
- Dependency.get(DialogTransitionAnimator::class.java),
- )
+ SystemUIDialog.Factory(
+ context,
+ Dependency.get(SystemUIDialogManager::class.java),
+ Dependency.get(SysUiState::class.java),
+ Dependency.get(BroadcastDispatcher::class.java),
+ Dependency.get(DialogTransitionAnimator::class.java),
+ )
val delegate =
ScreenRecordPermissionDialogDelegate(
@@ -189,6 +188,17 @@
verify(mediaProjectionMetricsLogger).notifyProjectionRequestCancelled(TEST_HOST_UID)
}
+ @Test
+ fun showDialog_singleAppSelected_clickOnStart_projectionRequestCancelledIsNotLoggedOnce() {
+ showDialog()
+ onSpinnerItemSelected(SINGLE_APP)
+
+ clickOnStart()
+
+ verify(mediaProjectionMetricsLogger, never())
+ .notifyProjectionRequestCancelled(TEST_HOST_UID)
+ }
+
private fun showDialog() {
dialog.show()
}
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 e957ca2..dfe72cf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -73,7 +73,7 @@
import com.android.keyguard.KeyguardStatusView;
import com.android.keyguard.KeyguardStatusViewController;
import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.LockIconViewController;
+import com.android.keyguard.LegacyLockIconViewController;
import com.android.keyguard.dagger.KeyguardQsUserSwitchComponent;
import com.android.keyguard.dagger.KeyguardStatusBarViewComponent;
import com.android.keyguard.dagger.KeyguardStatusViewComponent;
@@ -278,7 +278,7 @@
@Mock protected AmbientState mAmbientState;
@Mock protected UserManager mUserManager;
@Mock protected UiEventLogger mUiEventLogger;
- @Mock protected LockIconViewController mLockIconViewController;
+ @Mock protected LegacyLockIconViewController mLockIconViewController;
@Mock protected KeyguardViewConfigurator mKeyguardViewConfigurator;
@Mock protected KeyguardRootView mKeyguardRootView;
@Mock protected View mKeyguardRootViewChild;
@@ -604,6 +604,7 @@
new NotificationsKeyguardInteractor(notifsKeyguardViewStateRepository);
NotificationWakeUpCoordinator coordinator =
new NotificationWakeUpCoordinator(
+ mKosmos.getTestScope().getBackgroundScope(),
mDumpManager,
mock(HeadsUpManager.class),
new StatusBarStateControllerImpl(
@@ -618,7 +619,8 @@
mDozeParameters,
mScreenOffAnimationController,
new NotificationWakeUpCoordinatorLogger(logcatLogBuffer()),
- notifsKeyguardInteractor);
+ notifsKeyguardInteractor,
+ mKosmos.getCommunalInteractor());
mConfigurationController = new ConfigurationControllerImpl(mContext);
PulseExpansionHandler expansionHandler = new PulseExpansionHandler(
mContext,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
index 29a92d9..650c45b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
@@ -1061,7 +1061,7 @@
@Test
public void testPanelClosedWhenClosingQsInSplitShade() {
mShadeExpansionStateManager.onPanelExpansionChanged(/* fraction= */ 1,
- /* expanded= */ true, /* tracking= */ false, /* dragDownPxAmount= */ 0);
+ /* expanded= */ true, /* tracking= */ false);
enableSplitShade(/* enabled= */ true);
mNotificationPanelViewController.setExpandedFraction(1f);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
index b699613..dfbb699 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
@@ -25,7 +25,7 @@
import android.view.ViewGroup
import androidx.test.filters.SmallTest
import com.android.keyguard.KeyguardSecurityContainerController
-import com.android.keyguard.LockIconViewController
+import com.android.keyguard.LegacyLockIconViewController
import com.android.keyguard.dagger.KeyguardBouncerComponent
import com.android.systemui.Flags
import com.android.systemui.SysuiTestCase
@@ -46,6 +46,7 @@
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.res.R
import com.android.systemui.shade.NotificationShadeWindowView.InteractionEventHandler
+import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor
import com.android.systemui.statusbar.DragDownHelper
import com.android.systemui.statusbar.LockscreenShadeTransitionController
import com.android.systemui.statusbar.NotificationInsetsController
@@ -68,6 +69,7 @@
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
+import java.util.Optional
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.emptyFlow
@@ -85,7 +87,6 @@
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
-import java.util.Optional
import org.mockito.Mockito.`when` as whenever
@OptIn(ExperimentalCoroutinesApi::class)
@@ -100,7 +101,8 @@
@Mock private lateinit var dozeServiceHost: DozeServiceHost
@Mock private lateinit var dozeScrimController: DozeScrimController
@Mock private lateinit var dockManager: DockManager
- @Mock private lateinit var notificationPanelViewController: NotificationPanelViewController
+ @Mock private lateinit var shadeViewController: ShadeViewController
+ @Mock private lateinit var panelExpansionInteractor: PanelExpansionInteractor
@Mock private lateinit var notificationShadeDepthController: NotificationShadeDepthController
@Mock private lateinit var notificationShadeWindowController: NotificationShadeWindowController
@Mock private lateinit var keyguardUnlockAnimationController: KeyguardUnlockAnimationController
@@ -113,7 +115,7 @@
@Mock private lateinit var quickSettingsController: QuickSettingsControllerImpl
@Mock
private lateinit var lockscreenShadeTransitionController: LockscreenShadeTransitionController
- @Mock private lateinit var lockIconViewController: LockIconViewController
+ @Mock private lateinit var lockIconViewController: LegacyLockIconViewController
@Mock private lateinit var phoneStatusBarViewController: PhoneStatusBarViewController
@Mock private lateinit var pulsingGestureListener: PulsingGestureListener
@Mock
@@ -177,7 +179,8 @@
dockManager,
notificationShadeDepthController,
view,
- notificationPanelViewController,
+ shadeViewController,
+ panelExpansionInteractor,
ShadeExpansionStateManager(),
stackScrollLayoutController,
statusBarKeyguardViewManager,
@@ -263,7 +266,7 @@
testScope.runTest {
underTest.setStatusBarViewController(phoneStatusBarViewController)
whenever(statusBarWindowStateController.windowIsShowing()).thenReturn(true)
- whenever(notificationPanelViewController.isFullyCollapsed).thenReturn(true)
+ whenever(panelExpansionInteractor.isFullyCollapsed).thenReturn(true)
whenever(phoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat()))
.thenReturn(true)
whenever(phoneStatusBarViewController.sendTouchToView(DOWN_EVENT)).thenReturn(true)
@@ -282,7 +285,7 @@
whenever(phoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat()))
.thenReturn(true)
// Item we're testing
- whenever(notificationPanelViewController.isFullyCollapsed).thenReturn(false)
+ whenever(panelExpansionInteractor.isFullyCollapsed).thenReturn(false)
val returnVal = interactionEventHandler.handleDispatchTouchEvent(DOWN_EVENT)
@@ -295,7 +298,7 @@
testScope.runTest {
underTest.setStatusBarViewController(phoneStatusBarViewController)
whenever(statusBarWindowStateController.windowIsShowing()).thenReturn(true)
- whenever(notificationPanelViewController.isFullyCollapsed).thenReturn(true)
+ whenever(panelExpansionInteractor.isFullyCollapsed).thenReturn(true)
// Item we're testing
whenever(phoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat()))
.thenReturn(false)
@@ -310,7 +313,7 @@
fun handleDispatchTouchEvent_sbWindowNotShowing_noSendTouchToSbAndReturnsTrue() =
testScope.runTest {
underTest.setStatusBarViewController(phoneStatusBarViewController)
- whenever(notificationPanelViewController.isFullyCollapsed).thenReturn(true)
+ whenever(panelExpansionInteractor.isFullyCollapsed).thenReturn(true)
whenever(phoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat()))
.thenReturn(true)
// Item we're testing
@@ -327,7 +330,7 @@
testScope.runTest {
underTest.setStatusBarViewController(phoneStatusBarViewController)
whenever(statusBarWindowStateController.windowIsShowing()).thenReturn(true)
- whenever(notificationPanelViewController.isFullyCollapsed).thenReturn(true)
+ whenever(panelExpansionInteractor.isFullyCollapsed).thenReturn(true)
whenever(phoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat()))
.thenReturn(true)
@@ -486,7 +489,7 @@
// AND bouncer is not showing
whenever(centralSurfaces.isBouncerShowing()).thenReturn(false)
// AND panel view controller wants it
- whenever(notificationPanelViewController.handleExternalInterceptTouch(DOWN_EVENT))
+ whenever(shadeViewController.handleExternalInterceptTouch(DOWN_EVENT))
.thenReturn(true)
mSetFlagsRule.enableFlags(Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
index 2ecca2e..98a815c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
@@ -22,7 +22,7 @@
import android.widget.FrameLayout
import androidx.test.filters.SmallTest
import com.android.keyguard.KeyguardSecurityContainerController
-import com.android.keyguard.LockIconViewController
+import com.android.keyguard.LegacyLockIconViewController
import com.android.keyguard.dagger.KeyguardBouncerComponent
import com.android.systemui.Flags as AConfigFlags
import com.android.systemui.SysuiTestCase
@@ -38,6 +38,7 @@
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.res.R
import com.android.systemui.shade.NotificationShadeWindowView.InteractionEventHandler
+import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor
import com.android.systemui.statusbar.DragDownHelper
import com.android.systemui.statusbar.LockscreenShadeTransitionController
import com.android.systemui.statusbar.NotificationInsetsController
@@ -89,7 +90,8 @@
@Mock private lateinit var dozeServiceHost: DozeServiceHost
@Mock private lateinit var dozeScrimController: DozeScrimController
@Mock private lateinit var dockManager: DockManager
- @Mock private lateinit var notificationPanelViewController: NotificationPanelViewController
+ @Mock private lateinit var shadeViewController: ShadeViewController
+ @Mock private lateinit var panelExpansionInteractor: PanelExpansionInteractor
@Mock private lateinit var notificationStackScrollLayout: NotificationStackScrollLayout
@Mock private lateinit var notificationShadeDepthController: NotificationShadeDepthController
@Mock private lateinit var notificationShadeWindowController: NotificationShadeWindowController
@@ -101,7 +103,7 @@
@Mock private lateinit var statusBarWindowStateController: StatusBarWindowStateController
@Mock
private lateinit var lockscreenShadeTransitionController: LockscreenShadeTransitionController
- @Mock private lateinit var lockIconViewController: LockIconViewController
+ @Mock private lateinit var lockIconViewController: LegacyLockIconViewController
@Mock private lateinit var keyguardUnlockAnimationController: KeyguardUnlockAnimationController
@Mock private lateinit var ambientState: AmbientState
@Mock private lateinit var shadeLogger: ShadeLogger
@@ -166,7 +168,8 @@
dockManager,
notificationShadeDepthController,
underTest,
- notificationPanelViewController,
+ shadeViewController,
+ panelExpansionInteractor,
ShadeExpansionStateManager(),
notificationStackScrollLayoutController,
statusBarKeyguardViewManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeExpansionStateManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeExpansionStateManagerTest.kt
index 15c04eb..89ae42f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeExpansionStateManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeExpansionStateManagerTest.kt
@@ -42,17 +42,11 @@
val tracking = true
val dragDownAmount = 1234f
- shadeExpansionStateManager.onPanelExpansionChanged(
- fraction,
- expanded,
- tracking,
- dragDownAmount
- )
+ shadeExpansionStateManager.onPanelExpansionChanged(fraction, expanded, tracking)
assertThat(listener.fraction).isEqualTo(fraction)
assertThat(listener.expanded).isEqualTo(expanded)
assertThat(listener.tracking).isEqualTo(tracking)
- assertThat(listener.dragDownAmountPx).isEqualTo(dragDownAmount)
}
@Test
@@ -61,12 +55,7 @@
val expanded = true
val tracking = true
val dragDownAmount = 1234f
- shadeExpansionStateManager.onPanelExpansionChanged(
- fraction,
- expanded,
- tracking,
- dragDownAmount
- )
+ shadeExpansionStateManager.onPanelExpansionChanged(fraction, expanded, tracking)
val listener = TestShadeExpansionListener()
val currentState = shadeExpansionStateManager.addExpansionListener(listener)
@@ -75,7 +64,6 @@
assertThat(listener.fraction).isEqualTo(fraction)
assertThat(listener.expanded).isEqualTo(expanded)
assertThat(listener.tracking).isEqualTo(tracking)
- assertThat(listener.dragDownAmountPx).isEqualTo(dragDownAmount)
}
@Test
@@ -100,8 +88,7 @@
shadeExpansionStateManager.onPanelExpansionChanged(
fraction = 0.5f,
expanded = true,
- tracking = false,
- dragDownPxAmount = 0f
+ tracking = false
)
assertThat(listener.state).isEqualTo(STATE_OPENING)
@@ -115,8 +102,7 @@
shadeExpansionStateManager.onPanelExpansionChanged(
fraction = 0.5f,
expanded = true,
- tracking = true,
- dragDownPxAmount = 0f
+ tracking = true
)
assertThat(listener.state).isEqualTo(STATE_OPENING)
@@ -132,8 +118,7 @@
shadeExpansionStateManager.onPanelExpansionChanged(
fraction = 0.5f,
expanded = false,
- tracking = false,
- dragDownPxAmount = 0f
+ tracking = false
)
assertThat(listener.state).isEqualTo(STATE_CLOSED)
@@ -149,8 +134,7 @@
shadeExpansionStateManager.onPanelExpansionChanged(
fraction = 0.5f,
expanded = false,
- tracking = true,
- dragDownPxAmount = 0f
+ tracking = true
)
assertThat(listener.state).isEqualTo(STATE_OPEN)
@@ -166,8 +150,7 @@
shadeExpansionStateManager.onPanelExpansionChanged(
fraction = 1f,
expanded = true,
- tracking = false,
- dragDownPxAmount = 0f
+ tracking = false
)
assertThat(listener.previousState).isEqualTo(STATE_OPENING)
@@ -182,8 +165,7 @@
shadeExpansionStateManager.onPanelExpansionChanged(
fraction = 1f,
expanded = true,
- tracking = true,
- dragDownPxAmount = 0f
+ tracking = true
)
assertThat(listener.state).isEqualTo(STATE_OPENING)
@@ -199,8 +181,7 @@
shadeExpansionStateManager.onPanelExpansionChanged(
fraction = 1f,
expanded = false,
- tracking = false,
- dragDownPxAmount = 0f
+ tracking = false
)
assertThat(listener.state).isEqualTo(STATE_CLOSED)
@@ -216,8 +197,7 @@
shadeExpansionStateManager.onPanelExpansionChanged(
fraction = 1f,
expanded = false,
- tracking = true,
- dragDownPxAmount = 0f
+ tracking = true
)
assertThat(listener.state).isEqualTo(STATE_OPEN)
@@ -229,13 +209,11 @@
var fraction: Float = 0f
var expanded: Boolean = false
var tracking: Boolean = false
- var dragDownAmountPx: Float = 0f
override fun onPanelExpansionChanged(event: ShadeExpansionChangeEvent) {
this.fraction = event.fraction
this.expanded = event.expanded
this.tracking = event.tracking
- this.dragDownAmountPx = event.dragDownPxAmount
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt
index dea905a..f2abb90 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt
@@ -3,23 +3,18 @@
import android.platform.test.annotations.DisableFlags
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
-import com.android.compose.animation.scene.ObservableTransitionState
-import com.android.compose.animation.scene.SceneKey
import com.android.systemui.Flags
import com.android.systemui.SysuiTestCase
-import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepository
import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository
import com.android.systemui.deviceentry.domain.interactor.DeviceUnlockedInteractor
import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
import com.android.systemui.dump.DumpManager
-import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.testScope
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.shared.model.FakeSceneDataSource
-import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.shared.model.fakeSceneDataSource
import com.android.systemui.shade.ShadeExpansionChangeEvent
import com.android.systemui.shade.ShadeExpansionStateManager
@@ -27,15 +22,8 @@
import com.android.systemui.shade.domain.interactor.panelExpansionInteractor
import com.android.systemui.statusbar.phone.ScrimController
import com.android.systemui.testKosmos
-import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.whenever
-import com.google.common.truth.Truth
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.runCurrent
-import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -74,9 +62,7 @@
sceneInteractor = kosmos.sceneInteractor
fakeSceneDataSource = kosmos.fakeSceneDataSource
underTest = ScrimShadeTransitionController(
- applicationScope,
shadeExpansionStateManager,
- { panelExpansionInteractor },
dumpManager,
scrimController,
)
@@ -99,96 +85,20 @@
verify(scrimController).setRawPanelExpansionFraction(DEFAULT_EXPANSION_EVENT.fraction)
}
- @Test
- @EnableSceneContainer
- fun sceneChanges_forwardsToScrimTransitionController() =
- testScope.runTest {
- var rawExpansion: Float? = null
- whenever(scrimController.setRawPanelExpansionFraction(any())).then {
- (it.arguments[0] as Float?).also { rawExp -> rawExpansion = rawExp }
- }
- setUnlocked(true)
- val transitionState =
- MutableStateFlow<ObservableTransitionState>(
- ObservableTransitionState.Idle(Scenes.Gone)
- )
- sceneInteractor.setTransitionState(transitionState)
-
- changeScene(Scenes.Gone, transitionState)
- val currentScene by collectLastValue(sceneInteractor.currentScene)
- Truth.assertThat(currentScene).isEqualTo(Scenes.Gone)
-
- Truth.assertThat(rawExpansion)
- .isEqualTo(0f)
-
- changeScene(Scenes.Shade, transitionState) { progress ->
- Truth.assertThat(rawExpansion)
- .isEqualTo(progress)
- }
- }
-
private fun startLegacyPanelExpansion() {
shadeExpansionStateManager.onPanelExpansionChanged(
DEFAULT_EXPANSION_EVENT.fraction,
DEFAULT_EXPANSION_EVENT.expanded,
DEFAULT_EXPANSION_EVENT.tracking,
- DEFAULT_EXPANSION_EVENT.dragDownPxAmount,
)
}
- private fun TestScope.setUnlocked(isUnlocked: Boolean) {
- val isDeviceUnlocked by collectLastValue(deviceUnlockedInteractor.isDeviceUnlocked)
- deviceEntryRepository.setUnlocked(isUnlocked)
- runCurrent()
-
- Truth.assertThat(isDeviceUnlocked).isEqualTo(isUnlocked)
- }
-
- private fun TestScope.changeScene(
- toScene: SceneKey,
- transitionState: MutableStateFlow<ObservableTransitionState>,
- assertDuringProgress: ((progress: Float) -> Unit) = {},
- ) {
- val currentScene by collectLastValue(sceneInteractor.currentScene)
- val progressFlow = MutableStateFlow(0f)
- transitionState.value =
- ObservableTransitionState.Transition(
- fromScene = checkNotNull(currentScene),
- toScene = toScene,
- progress = progressFlow,
- isInitiatedByUserInput = true,
- isUserInputOngoing = flowOf(true),
- )
- runCurrent()
- assertDuringProgress(progressFlow.value)
-
- progressFlow.value = 0.2f
- runCurrent()
- assertDuringProgress(progressFlow.value)
-
- progressFlow.value = 0.6f
- runCurrent()
- assertDuringProgress(progressFlow.value)
-
- progressFlow.value = 1f
- runCurrent()
- assertDuringProgress(progressFlow.value)
-
- transitionState.value = ObservableTransitionState.Idle(toScene)
- fakeSceneDataSource.changeScene(toScene)
- runCurrent()
- assertDuringProgress(progressFlow.value)
-
- Truth.assertThat(currentScene).isEqualTo(toScene)
- }
-
companion object {
val DEFAULT_EXPANSION_EVENT =
ShadeExpansionChangeEvent(
fraction = 0.5f,
expanded = true,
- tracking = true,
- dragDownPxAmount = 10f
+ tracking = true
)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
index 68bc72b..fc0c85e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
@@ -23,18 +23,18 @@
import android.view.View
import android.view.ViewRootImpl
import androidx.test.filters.SmallTest
-import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.ShadeInterpolation
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.res.R
import com.android.systemui.shade.ShadeExpansionChangeEvent
import com.android.systemui.statusbar.phone.BiometricUnlockController
import com.android.systemui.statusbar.phone.DozeParameters
import com.android.systemui.statusbar.phone.ScrimController
import com.android.systemui.statusbar.policy.FakeConfigurationController
-import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController
import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController
import com.android.systemui.util.WallpaperController
import com.android.systemui.util.mockito.eq
import com.google.common.truth.Truth.assertThat
@@ -142,7 +142,7 @@
fun onPanelExpansionChanged_apliesBlur_ifShade() {
notificationShadeDepthController.onPanelExpansionChanged(
ShadeExpansionChangeEvent(
- fraction = 1f, expanded = true, tracking = false, dragDownPxAmount = 0f))
+ fraction = 1f, expanded = true, tracking = false))
verify(shadeAnimation).animateTo(eq(maxBlur))
}
@@ -150,7 +150,7 @@
fun onPanelExpansionChanged_animatesBlurIn_ifShade() {
notificationShadeDepthController.onPanelExpansionChanged(
ShadeExpansionChangeEvent(
- fraction = 0.01f, expanded = false, tracking = false, dragDownPxAmount = 0f))
+ fraction = 0.01f, expanded = false, tracking = false))
verify(shadeAnimation).animateTo(eq(maxBlur))
}
@@ -160,7 +160,7 @@
clearInvocations(shadeAnimation)
notificationShadeDepthController.onPanelExpansionChanged(
ShadeExpansionChangeEvent(
- fraction = 0f, expanded = false, tracking = false, dragDownPxAmount = 0f))
+ fraction = 0f, expanded = false, tracking = false))
verify(shadeAnimation).animateTo(eq(0))
}
@@ -168,7 +168,7 @@
fun onPanelExpansionChanged_animatesBlurOut_ifFlick() {
val event =
ShadeExpansionChangeEvent(
- fraction = 1f, expanded = true, tracking = false, dragDownPxAmount = 0f)
+ fraction = 1f, expanded = true, tracking = false)
onPanelExpansionChanged_apliesBlur_ifShade()
clearInvocations(shadeAnimation)
notificationShadeDepthController.onPanelExpansionChanged(event)
@@ -189,7 +189,7 @@
clearInvocations(shadeAnimation)
notificationShadeDepthController.onPanelExpansionChanged(
ShadeExpansionChangeEvent(
- fraction = 0.6f, expanded = true, tracking = true, dragDownPxAmount = 0f))
+ fraction = 0.6f, expanded = true, tracking = true))
verify(shadeAnimation).animateTo(eq(maxBlur))
}
@@ -197,7 +197,7 @@
fun onPanelExpansionChanged_respectsMinPanelPullDownFraction() {
val event =
ShadeExpansionChangeEvent(
- fraction = 0.5f, expanded = true, tracking = true, dragDownPxAmount = 0f)
+ fraction = 0.5f, expanded = true, tracking = true)
notificationShadeDepthController.panelPullDownMinFraction = 0.5f
notificationShadeDepthController.onPanelExpansionChanged(event)
assertThat(notificationShadeDepthController.shadeExpansion).isEqualTo(0f)
@@ -225,7 +225,7 @@
notificationShadeDepthController.qsPanelExpansion = 1f
notificationShadeDepthController.onPanelExpansionChanged(
ShadeExpansionChangeEvent(
- fraction = 1f, expanded = true, tracking = false, dragDownPxAmount = 0f))
+ fraction = 1f, expanded = true, tracking = false))
notificationShadeDepthController.updateBlurCallback.doFrame(0)
verify(blurUtils).applyBlur(any(), eq(maxBlur), eq(false))
}
@@ -236,7 +236,7 @@
notificationShadeDepthController.qsPanelExpansion = 0.25f
notificationShadeDepthController.onPanelExpansionChanged(
ShadeExpansionChangeEvent(
- fraction = 1f, expanded = true, tracking = false, dragDownPxAmount = 0f))
+ fraction = 1f, expanded = true, tracking = false))
notificationShadeDepthController.updateBlurCallback.doFrame(0)
verify(wallpaperController)
.setNotificationShadeZoom(eq(ShadeInterpolation.getNotificationScrimAlpha(0.25f)))
@@ -248,7 +248,7 @@
notificationShadeDepthController.onPanelExpansionChanged(
ShadeExpansionChangeEvent(
- fraction = 1f, expanded = true, tracking = false, dragDownPxAmount = 0f))
+ fraction = 1f, expanded = true, tracking = false))
notificationShadeDepthController.updateBlurCallback.doFrame(0)
verify(wallpaperController).setNotificationShadeZoom(0f)
@@ -260,7 +260,7 @@
notificationShadeDepthController.onPanelExpansionChanged(
ShadeExpansionChangeEvent(
- fraction = 1f, expanded = true, tracking = false, dragDownPxAmount = 0f))
+ fraction = 1f, expanded = true, tracking = false))
notificationShadeDepthController.updateBlurCallback.doFrame(0)
verify(wallpaperController).setNotificationShadeZoom(floatThat { it > 0 })
@@ -273,7 +273,7 @@
val expanded = true
val tracking = false
val dragDownPxAmount = 0f
- val event = ShadeExpansionChangeEvent(rawFraction, expanded, tracking, dragDownPxAmount)
+ val event = ShadeExpansionChangeEvent(rawFraction, expanded, tracking)
val inOrder = Mockito.inOrder(wallpaperController)
notificationShadeDepthController.onPanelExpansionChanged(event)
@@ -338,7 +338,7 @@
fun updateBlurCallback_setsBlur_whenExpanded() {
notificationShadeDepthController.onPanelExpansionChanged(
ShadeExpansionChangeEvent(
- fraction = 1f, expanded = true, tracking = false, dragDownPxAmount = 0f))
+ fraction = 1f, expanded = true, tracking = false))
`when`(shadeAnimation.radius).thenReturn(maxBlur.toFloat())
notificationShadeDepthController.updateBlurCallback.doFrame(0)
verify(blurUtils).applyBlur(any(), eq(maxBlur), eq(false))
@@ -348,7 +348,7 @@
fun updateBlurCallback_ignoreShadeBlurUntilHidden_overridesZoom() {
notificationShadeDepthController.onPanelExpansionChanged(
ShadeExpansionChangeEvent(
- fraction = 1f, expanded = true, tracking = false, dragDownPxAmount = 0f))
+ fraction = 1f, expanded = true, tracking = false))
`when`(shadeAnimation.radius).thenReturn(maxBlur.toFloat())
notificationShadeDepthController.blursDisabledForAppLaunch = true
notificationShadeDepthController.updateBlurCallback.doFrame(0)
@@ -367,7 +367,7 @@
fun ignoreBlurForUnlock_ignores() {
notificationShadeDepthController.onPanelExpansionChanged(
ShadeExpansionChangeEvent(
- fraction = 1f, expanded = true, tracking = false, dragDownPxAmount = 0f))
+ fraction = 1f, expanded = true, tracking = false))
`when`(shadeAnimation.radius).thenReturn(maxBlur.toFloat())
notificationShadeDepthController.blursDisabledForAppLaunch = false
@@ -384,7 +384,7 @@
fun ignoreBlurForUnlock_doesNotIgnore() {
notificationShadeDepthController.onPanelExpansionChanged(
ShadeExpansionChangeEvent(
- fraction = 1f, expanded = true, tracking = false, dragDownPxAmount = 0f))
+ fraction = 1f, expanded = true, tracking = false))
`when`(shadeAnimation.radius).thenReturn(maxBlur.toFloat())
notificationShadeDepthController.blursDisabledForAppLaunch = false
@@ -416,7 +416,7 @@
// And shade is blurred
notificationShadeDepthController.onPanelExpansionChanged(
ShadeExpansionChangeEvent(
- fraction = 1f, expanded = true, tracking = false, dragDownPxAmount = 0f))
+ fraction = 1f, expanded = true, tracking = false))
`when`(shadeAnimation.radius).thenReturn(maxBlur.toFloat())
notificationShadeDepthController.updateBlurCallback.doFrame(0)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/OperatorNameViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/OperatorNameViewControllerTest.kt
new file mode 100644
index 0000000..9c59f9b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/OperatorNameViewControllerTest.kt
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar
+
+import android.telephony.ServiceState
+import android.telephony.SubscriptionInfo
+import android.telephony.TelephonyManager
+import android.telephony.telephonyManager
+import androidx.test.filters.SmallTest
+import com.android.keyguard.keyguardUpdateMonitor
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.plugins.DarkIconDispatcher
+import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
+import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
+import com.android.systemui.statusbar.pipeline.mobile.util.FakeSubscriptionManagerProxy
+import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
+import com.android.systemui.tuner.TunerService
+import com.android.systemui.util.CarrierConfigTracker
+import com.android.systemui.util.kotlin.JavaAdapter
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import junit.framework.Assert.assertTrue
+import kotlin.test.Test
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+class OperatorNameViewControllerTest : SysuiTestCase() {
+ private lateinit var underTest: OperatorNameViewController
+ private lateinit var airplaneModeInteractor: AirplaneModeInteractor
+
+ private val kosmos = Kosmos()
+ private val testScope = TestScope()
+
+ private val view = OperatorNameView(mContext)
+ private val javaAdapter = JavaAdapter(testScope.backgroundScope)
+
+ @Mock private lateinit var darkIconDispatcher: DarkIconDispatcher
+ @Mock private lateinit var tunerService: TunerService
+ private var telephonyManager = kosmos.telephonyManager
+ private val keyguardUpdateMonitor = kosmos.keyguardUpdateMonitor
+ @Mock private lateinit var carrierConfigTracker: CarrierConfigTracker
+ private val subscriptionManagerProxy = FakeSubscriptionManagerProxy()
+
+ private val airplaneModeRepository = FakeAirplaneModeRepository()
+ private val connectivityRepository = FakeConnectivityRepository()
+ private val mobileConnectionsRepository = FakeMobileConnectionsRepository()
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+
+ airplaneModeInteractor =
+ AirplaneModeInteractor(
+ airplaneModeRepository,
+ connectivityRepository,
+ mobileConnectionsRepository,
+ )
+
+ underTest =
+ OperatorNameViewController.Factory(
+ darkIconDispatcher,
+ tunerService,
+ telephonyManager,
+ keyguardUpdateMonitor,
+ carrierConfigTracker,
+ airplaneModeInteractor,
+ subscriptionManagerProxy,
+ javaAdapter,
+ )
+ .create(view)
+ }
+
+ @Test
+ fun updateFromSubInfo_showsCarrieName() =
+ testScope.runTest {
+ whenever(telephonyManager.isDataCapable).thenReturn(true)
+
+ val mockSubInfo =
+ mock<SubscriptionInfo>().also {
+ whenever(it.subscriptionId).thenReturn(1)
+ whenever(it.carrierName).thenReturn("test_carrier")
+ }
+ whenever(keyguardUpdateMonitor.getSubscriptionInfoForSubId(any()))
+ .thenReturn(mockSubInfo)
+ whenever(keyguardUpdateMonitor.getSimState(any()))
+ .thenReturn(TelephonyManager.SIM_STATE_READY)
+ whenever(keyguardUpdateMonitor.getServiceState(any()))
+ .thenReturn(ServiceState().also { it.state = ServiceState.STATE_IN_SERVICE })
+ subscriptionManagerProxy.defaultDataSubId = 1
+ airplaneModeRepository.setIsAirplaneMode(false)
+
+ underTest.onViewAttached()
+ runCurrent()
+
+ assertThat(view.text).isEqualTo("test_carrier")
+ }
+
+ @Test
+ fun notDataCapable_doesNotShowOperatorName() =
+ testScope.runTest {
+ whenever(telephonyManager.isDataCapable).thenReturn(false)
+
+ val mockSubInfo =
+ mock<SubscriptionInfo>().also {
+ whenever(it.subscriptionId).thenReturn(1)
+ whenever(it.carrierName).thenReturn("test_carrier")
+ }
+ whenever(keyguardUpdateMonitor.getSubscriptionInfoForSubId(any()))
+ .thenReturn(mockSubInfo)
+ whenever(keyguardUpdateMonitor.getSimState(any()))
+ .thenReturn(TelephonyManager.SIM_STATE_READY)
+ whenever(keyguardUpdateMonitor.getServiceState(any()))
+ .thenReturn(ServiceState().also { it.state = ServiceState.STATE_IN_SERVICE })
+ subscriptionManagerProxy.defaultDataSubId = 1
+ airplaneModeRepository.setIsAirplaneMode(false)
+
+ underTest.onViewAttached()
+ runCurrent()
+
+ assertTrue(view.text.isNullOrEmpty())
+ }
+
+ @Test
+ fun airplaneMode_doesNotShowOperatorName() =
+ testScope.runTest {
+ whenever(telephonyManager.isDataCapable).thenReturn(false)
+ val mockSubInfo =
+ mock<SubscriptionInfo>().also {
+ whenever(it.subscriptionId).thenReturn(1)
+ whenever(it.carrierName).thenReturn("test_carrier")
+ }
+ whenever(keyguardUpdateMonitor.getSubscriptionInfoForSubId(any()))
+ .thenReturn(mockSubInfo)
+ whenever(keyguardUpdateMonitor.getSimState(any()))
+ .thenReturn(TelephonyManager.SIM_STATE_READY)
+ whenever(keyguardUpdateMonitor.getServiceState(any()))
+ .thenReturn(ServiceState().also { it.state = ServiceState.STATE_IN_SERVICE })
+ subscriptionManagerProxy.defaultDataSubId = 1
+ airplaneModeRepository.setIsAirplaneMode(true)
+
+ underTest.onViewAttached()
+ runCurrent()
+
+ assertTrue(view.text.isNullOrEmpty())
+ }
+
+ @Test
+ fun notInService_doesNotShowOperatorName() =
+ testScope.runTest {
+ // Data capable
+ whenever(telephonyManager.isDataCapable).thenReturn(true)
+
+ // Valid subscription
+ val mockSubInfo =
+ mock<SubscriptionInfo>().also {
+ whenever(it.subscriptionId).thenReturn(1)
+ whenever(it.carrierName).thenReturn("test_carrier")
+ }
+ whenever(keyguardUpdateMonitor.getSubscriptionInfoForSubId(any()))
+ .thenReturn(mockSubInfo)
+ whenever(keyguardUpdateMonitor.getSimState(any()))
+ .thenReturn(TelephonyManager.SIM_STATE_READY)
+
+ // Not in service
+ whenever(keyguardUpdateMonitor.getServiceState(any()))
+ .thenReturn(ServiceState().also { it.state = ServiceState.STATE_OUT_OF_SERVICE })
+ // Subscription is default for data
+ subscriptionManagerProxy.defaultDataSubId = 1
+ // Not airplane mode
+ airplaneModeRepository.setIsAirplaneMode(false)
+
+ underTest.onViewAttached()
+ runCurrent()
+
+ assertTrue(view.text.isNullOrEmpty())
+ }
+}
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 82093ad..67b540c 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
@@ -19,10 +19,15 @@
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.ObservableTransitionState
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.AnimatorTestRule
+import com.android.systemui.communal.data.repository.communalRepository
+import com.android.systemui.communal.domain.interactor.communalInteractor
+import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.dump.DumpManager
-import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.testScope
import com.android.systemui.log.logcatLogBuffer
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.shade.ShadeViewController.Companion.WAKEUP_ANIMATION_DELAY_MS
@@ -34,11 +39,16 @@
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.phone.ScreenOffAnimationController
import com.android.systemui.statusbar.policy.HeadsUpManager
+import com.android.systemui.testKosmos
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.mockito.withArgCaptor
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@@ -49,6 +59,7 @@
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
+@OptIn(ExperimentalCoroutinesApi::class)
@RunWith(AndroidTestingRunner::class)
@SmallTest
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@@ -56,7 +67,8 @@
@get:Rule val animatorTestRule = AnimatorTestRule(this)
- private val kosmos = Kosmos()
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
private val dumpManager: DumpManager = mock()
private val headsUpManager: HeadsUpManager = mock()
@@ -97,6 +109,7 @@
whenever(statusBarStateController.state).then { statusBarState }
notificationWakeUpCoordinator =
NotificationWakeUpCoordinator(
+ kosmos.applicationCoroutineScope,
dumpManager,
headsUpManager,
statusBarStateController,
@@ -105,6 +118,7 @@
screenOffAnimationController,
logger,
kosmos.notificationsKeyguardInteractor,
+ kosmos.communalInteractor,
)
statusBarStateCallback = withArgCaptor {
verify(statusBarStateController).addCallback(capture())
@@ -161,6 +175,39 @@
}
@Test
+ fun setDozeToZeroWhenCommunalShowingWillFullyHideNotifications() =
+ testScope.runTest {
+ val transitionState =
+ MutableStateFlow<ObservableTransitionState>(
+ ObservableTransitionState.Idle(CommunalScenes.Communal)
+ )
+ kosmos.communalRepository.setTransitionState(transitionState)
+ runCurrent()
+ setDozeAmount(0f)
+ verifyStackScrollerDozeAndHideAmount(dozeAmount = 1f, hideAmount = 1f)
+ assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isTrue()
+ }
+
+ @Test
+ fun closingCommunalWillShowNotifications() =
+ testScope.runTest {
+ val transitionState =
+ MutableStateFlow<ObservableTransitionState>(
+ ObservableTransitionState.Idle(CommunalScenes.Communal)
+ )
+ kosmos.communalRepository.setTransitionState(transitionState)
+ runCurrent()
+ setDozeAmount(0f)
+ verifyStackScrollerDozeAndHideAmount(dozeAmount = 1f, hideAmount = 1f)
+ assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isTrue()
+
+ transitionState.value = ObservableTransitionState.Idle(CommunalScenes.Blank)
+ runCurrent()
+ verifyStackScrollerDozeAndHideAmount(dozeAmount = 0f, hideAmount = 0f)
+ assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isFalse()
+ }
+
+ @Test
fun switchingToShadeWithBypassEnabledWillShowNotifications() {
setDozeToZeroWithBypassWillFullyHideNotifications()
clearInvocations(stackScrollerController)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index 054680d..34605fe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -597,8 +597,7 @@
private static ShadeExpansionChangeEvent expansionEvent(
float fraction, boolean expanded, boolean tracking) {
- return new ShadeExpansionChangeEvent(
- fraction, expanded, tracking, /* dragDownPxAmount= */ 0f);
+ return new ShadeExpansionChangeEvent(fraction, expanded, tracking);
}
@Test
@@ -607,7 +606,7 @@
/* verify that a predictive back callback is registered when the bouncer becomes visible */
mBouncerExpansionCallback.onVisibilityChanged(true);
verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
- eq(OnBackInvokedDispatcher.PRIORITY_OVERLAY),
+ eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT),
mBackCallbackCaptor.capture());
/* verify that the same callback is unregistered when the bouncer becomes invisible */
@@ -622,7 +621,7 @@
mBouncerExpansionCallback.onVisibilityChanged(true);
/* capture the predictive back callback during registration */
verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
- eq(OnBackInvokedDispatcher.PRIORITY_OVERLAY),
+ eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT),
mBackCallbackCaptor.capture());
when(mPrimaryBouncerInteractor.isFullyShowing()).thenReturn(true);
@@ -642,7 +641,7 @@
mBouncerExpansionCallback.onVisibilityChanged(true);
/* capture the predictive back callback during registration */
verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
- eq(OnBackInvokedDispatcher.PRIORITY_OVERLAY),
+ eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT),
mBackCallbackCaptor.capture());
assertTrue(mBackCallbackCaptor.getValue() instanceof OnBackAnimationCallback);
@@ -660,7 +659,7 @@
mBouncerExpansionCallback.onVisibilityChanged(true);
/* capture the predictive back callback during registration */
verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
- eq(OnBackInvokedDispatcher.PRIORITY_OVERLAY),
+ eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT),
mBackCallbackCaptor.capture());
assertTrue(mBackCallbackCaptor.getValue() instanceof OnBackAnimationCallback);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
index 3da5ab9..9c3d9c6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
@@ -52,7 +52,7 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.res.R;
import com.android.systemui.shade.ShadeExpansionStateManager;
-import com.android.systemui.shade.ShadeViewController;
+import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.OperatorNameViewController;
import com.android.systemui.statusbar.disableflags.DisableFlagsLogger;
@@ -115,7 +115,7 @@
@Mock
private HeadsUpAppearanceController mHeadsUpAppearanceController;
@Mock
- private ShadeViewController mShadeViewController;
+ private PanelExpansionInteractor mPanelExpansionInteractor;
@Mock
private StatusBarIconController.DarkIconManager.Factory mIconManagerFactory;
@Mock
@@ -304,7 +304,7 @@
// WHEN the shade is open and configured to hide the status bar icons
mShadeExpansionStateManager.updateState(STATE_OPEN);
- when(mShadeViewController.shouldHideStatusBarIconsWhenExpanded()).thenReturn(true);
+ when(mPanelExpansionInteractor.shouldHideStatusBarIconsWhenExpanded()).thenReturn(true);
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
@@ -320,7 +320,7 @@
// WHEN the shade is open but *not* configured to hide the status bar icons
mShadeExpansionStateManager.updateState(STATE_OPEN);
- when(mShadeViewController.shouldHideStatusBarIconsWhenExpanded()).thenReturn(false);
+ when(mPanelExpansionInteractor.shouldHideStatusBarIconsWhenExpanded()).thenReturn(false);
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
@@ -337,7 +337,7 @@
// WHEN the shade is open and configured to hide the status bar icons
mShadeExpansionStateManager.updateState(STATE_OPEN);
- when(mShadeViewController.shouldHideStatusBarIconsWhenExpanded()).thenReturn(true);
+ when(mPanelExpansionInteractor.shouldHideStatusBarIconsWhenExpanded()).thenReturn(true);
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
@@ -696,7 +696,7 @@
mCollapsedStatusBarViewBinder,
mStatusBarHideIconsForBouncerManager,
mKeyguardStateController,
- mShadeViewController,
+ mPanelExpansionInteractor,
mStatusBarStateController,
mock(NotificationIconContainerStatusBarViewBinder.class),
mCommandQueue,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt
index 867476f..581ca3b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt
@@ -28,6 +28,7 @@
import android.content.pm.PackageManager
import android.media.projection.MediaProjectionInfo
import android.media.projection.MediaProjectionManager
+import android.os.UserHandle
import android.permission.flags.Flags.FLAG_SENSITIVE_NOTIFICATION_APP_PROTECTION
import android.platform.test.annotations.EnableFlags
import android.platform.test.annotations.RequiresFlagsDisabled
@@ -85,7 +86,6 @@
@Mock private lateinit var activityManager: IActivityManager
@Mock private lateinit var mediaProjectionManager: MediaProjectionManager
@Mock private lateinit var packageManager: PackageManager
- @Mock private lateinit var mediaProjectionInfo: MediaProjectionInfo
@Mock private lateinit var listener1: Runnable
@Mock private lateinit var listener2: Runnable
@Mock private lateinit var listener3: Runnable
@@ -95,6 +95,7 @@
private lateinit var globalSettings: FakeGlobalSettings
private lateinit var mediaProjectionCallback: MediaProjectionManager.Callback
private lateinit var controller: SensitiveNotificationProtectionControllerImpl
+ private lateinit var mediaProjectionInfo: MediaProjectionInfo
@Before
fun setUp() {
@@ -109,14 +110,29 @@
setShareFullScreen()
whenever(activityManager.bugreportWhitelistedPackages)
.thenReturn(listOf(BUGREPORT_PACKAGE_NAME))
- whenever(packageManager.getPackageUid(TEST_PROJECTION_PACKAGE_NAME, 0))
+ whenever(
+ packageManager.getPackageUidAsUser(
+ TEST_PROJECTION_PACKAGE_NAME,
+ UserHandle.CURRENT.identifier
+ )
+ )
.thenReturn(TEST_PROJECTION_PACKAGE_UID)
- whenever(packageManager.getPackageUid(BUGREPORT_PACKAGE_NAME, 0))
+ whenever(
+ packageManager.getPackageUidAsUser(
+ BUGREPORT_PACKAGE_NAME,
+ UserHandle.CURRENT.identifier
+ )
+ )
.thenReturn(BUGREPORT_PACKAGE_UID)
// SystemUi context package name is exempt, but in test scenarios its
// com.android.systemui.tests so use that instead of hardcoding. Setup packagemanager to
// return the correct uid in this scenario
- whenever(packageManager.getPackageUid(mContext.packageName, 0))
+ whenever(
+ packageManager.getPackageUidAsUser(
+ mContext.packageName,
+ UserHandle.CURRENT.identifier
+ )
+ )
.thenReturn(mContext.applicationInfo.uid)
whenever(packageManager.checkPermission(anyString(), anyString()))
@@ -271,7 +287,7 @@
fun isSensitiveStateActive_projectionActive_sysuiExempt_false() {
// SystemUi context package name is exempt, but in test scenarios its
// com.android.systemui.tests so use that instead of hardcoding
- whenever(mediaProjectionInfo.packageName).thenReturn(mContext.packageName)
+ setShareFullScreenViaSystemUi()
mediaProjectionCallback.onStart(mediaProjectionInfo)
assertFalse(controller.isSensitiveStateActive)
@@ -309,7 +325,7 @@
@Test
fun isSensitiveStateActive_projectionActive_bugReportHandlerExempt_false() {
- whenever(mediaProjectionInfo.packageName).thenReturn(BUGREPORT_PACKAGE_NAME)
+ setShareFullScreenViaBugReportHandler()
mediaProjectionCallback.onStart(mediaProjectionInfo)
assertFalse(controller.isSensitiveStateActive)
@@ -371,7 +387,7 @@
fun shouldProtectNotification_projectionActive_sysuiExempt_false() {
// SystemUi context package name is exempt, but in test scenarios its
// com.android.systemui.tests so use that instead of hardcoding
- whenever(mediaProjectionInfo.packageName).thenReturn(mContext.packageName)
+ setShareFullScreenViaSystemUi()
mediaProjectionCallback.onStart(mediaProjectionInfo)
val notificationEntry = setupNotificationEntry(TEST_PACKAGE_NAME, false)
@@ -415,7 +431,7 @@
@Test
fun shouldProtectNotification_projectionActive_bugReportHandlerExempt_false() {
- whenever(mediaProjectionInfo.packageName).thenReturn(BUGREPORT_PACKAGE_NAME)
+ setShareFullScreenViaBugReportHandler()
mediaProjectionCallback.onStart(mediaProjectionInfo)
val notificationEntry = setupNotificationEntry(TEST_PACKAGE_NAME, false)
@@ -548,9 +564,7 @@
fun logSensitiveContentProtectionSession_exemptViaSystemUi() {
// SystemUi context package name is exempt, but in test scenarios its
// com.android.systemui.tests so use that instead of hardcoding
- val testPackageName = mContext.packageName
- val testUid = mContext.applicationInfo.uid
- whenever(mediaProjectionInfo.packageName).thenReturn(testPackageName)
+ setShareFullScreenViaSystemUi()
mediaProjectionCallback.onStart(mediaProjectionInfo)
@@ -558,7 +572,7 @@
FrameworkStatsLog.write(
eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION),
anyLong(),
- eq(testUid),
+ eq(mContext.applicationInfo.uid),
eq(true),
eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__STATE__START),
eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI)
@@ -571,7 +585,7 @@
FrameworkStatsLog.write(
eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION),
anyLong(),
- eq(testUid),
+ eq(mContext.applicationInfo.uid),
eq(true),
eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__STATE__STOP),
eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI)
@@ -582,8 +596,7 @@
@Test
fun logSensitiveContentProtectionSession_exemptViaBugReportHandler() {
// Setup exempt via bugreport handler
- whenever(mediaProjectionInfo.packageName).thenReturn(BUGREPORT_PACKAGE_NAME)
-
+ setShareFullScreenViaBugReportHandler()
mediaProjectionCallback.onStart(mediaProjectionInfo)
verify {
@@ -619,13 +632,26 @@
}
private fun setShareFullScreen() {
- whenever(mediaProjectionInfo.packageName).thenReturn(TEST_PROJECTION_PACKAGE_NAME)
- whenever(mediaProjectionInfo.launchCookie).thenReturn(null)
+ setShareScreen(TEST_PROJECTION_PACKAGE_NAME, true)
+ }
+
+ private fun setShareFullScreenViaBugReportHandler() {
+ setShareScreen(BUGREPORT_PACKAGE_NAME, true)
+ }
+
+ private fun setShareFullScreenViaSystemUi() {
+ // SystemUi context package name is exempt, but in test scenarios its
+ // com.android.systemui.tests so use that instead of hardcoding
+ setShareScreen(mContext.packageName, true)
}
private fun setShareSingleApp() {
- whenever(mediaProjectionInfo.packageName).thenReturn(TEST_PROJECTION_PACKAGE_NAME)
- whenever(mediaProjectionInfo.launchCookie).thenReturn(ActivityOptions.LaunchCookie())
+ setShareScreen(TEST_PROJECTION_PACKAGE_NAME, false)
+ }
+
+ private fun setShareScreen(packageName: String, fullScreen: Boolean) {
+ val launchCookie = if (fullScreen) null else ActivityOptions.LaunchCookie()
+ mediaProjectionInfo = MediaProjectionInfo(packageName, UserHandle.CURRENT, launchCookie)
}
private fun setupNotificationEntry(
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 fccb936..dc5597a 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
@@ -29,6 +29,7 @@
import static org.mockito.Mockito.when;
import android.app.PendingIntent;
+import android.app.role.RoleManager;
import android.content.Intent;
import android.service.quickaccesswallet.GetWalletCardsRequest;
import android.service.quickaccesswallet.QuickAccessWalletClient;
@@ -54,11 +55,14 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.List;
+
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
public class QuickAccessWalletControllerTest extends SysuiTestCase {
+ private static final String WALLET_ROLE_HOLDER = "wallet.role.holder";
@Mock
private QuickAccessWalletClient mQuickAccessWalletClient;
@Mock
@@ -69,6 +73,8 @@
private ActivityStarter mActivityStarter;
@Mock
private ActivityTransitionAnimator.Controller mAnimationController;
+ @Mock
+ private RoleManager mRoleManager;
@Captor
private ArgumentCaptor<GetWalletCardsRequest> mRequestCaptor;
@Captor
@@ -102,7 +108,8 @@
MoreExecutors.directExecutor(),
mSecureSettings,
mQuickAccessWalletClient,
- mClock);
+ mClock,
+ mRoleManager);
}
@Test
@@ -113,6 +120,24 @@
}
@Test
+ public void walletRoleAvailable_isAvailable() {
+ when(mRoleManager.isRoleAvailable(eq(RoleManager.ROLE_WALLET))).thenReturn(true);
+ when(mRoleManager.getRoleHolders(eq(RoleManager.ROLE_WALLET)))
+ .thenReturn(List.of(WALLET_ROLE_HOLDER));
+
+ assertTrue(mController.isWalletRoleAvailable());
+ }
+
+ @Test
+ public void walletRoleAvailable_isNotAvailable() {
+ when(mRoleManager.isRoleAvailable(eq(RoleManager.ROLE_WALLET))).thenReturn(false);
+ when(mRoleManager.getRoleHolders(eq(RoleManager.ROLE_WALLET)))
+ .thenReturn(List.of(WALLET_ROLE_HOLDER));
+
+ assertFalse(mController.isWalletRoleAvailable());
+ }
+
+ @Test
public void walletServiceUnavailable_walletNotEnabled() {
when(mQuickAccessWalletClient.isWalletServiceAvailable()).thenReturn(false);
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt
index 513c6ab..4a2eaf0 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt
@@ -27,6 +27,7 @@
import com.android.systemui.log.LogBuffer
import com.android.systemui.plugins.statusbar.statusBarStateController
import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.NotificationShadeWindowController
@@ -78,4 +79,11 @@
{ mock<NotificationGutsManager>() },
)
}
-var Kosmos.shadeController: ShadeController by Kosmos.Fixture { shadeControllerImpl }
+var Kosmos.shadeController: ShadeController by
+ Kosmos.Fixture {
+ if (SceneContainerFlag.isEnabled) {
+ shadeControllerSceneImpl
+ } else {
+ shadeControllerImpl
+ }
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/startable/ShadeStartableKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/startable/ShadeStartableKosmos.kt
index 7dfa686..b85858d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/startable/ShadeStartableKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/startable/ShadeStartableKosmos.kt
@@ -22,11 +22,17 @@
import com.android.systemui.kosmos.Kosmos.Fixture
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.log.LogBuffer
+import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.shade.ShadeExpansionStateManager
import com.android.systemui.shade.data.repository.shadeRepository
+import com.android.systemui.shade.domain.interactor.panelExpansionInteractor
import com.android.systemui.shade.transition.ScrimShadeTransitionController
import com.android.systemui.statusbar.policy.splitShadeStateController
import com.android.systemui.util.mockito.mock
+@Deprecated("ShadeExpansionStateManager is deprecated. Remove your dependency on it instead.")
+val Kosmos.shadeExpansionStateManager by Fixture { ShadeExpansionStateManager() }
+
val Kosmos.shadeStartable by Fixture {
ShadeStartable(
applicationScope = applicationCoroutineScope,
@@ -34,7 +40,10 @@
touchLog = mock<LogBuffer>(),
configurationRepository = configurationRepository,
shadeRepository = shadeRepository,
- controller = splitShadeStateController,
+ splitShadeStateController = splitShadeStateController,
scrimShadeTransitionController = mock<ScrimShadeTransitionController>(),
+ sceneInteractorProvider = { sceneInteractor },
+ panelExpansionInteractorProvider = { panelExpansionInteractor },
+ shadeExpansionStateManager = shadeExpansionStateManager,
)
}
diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp
index f4337d4..8905ad3 100644
--- a/ravenwood/Android.bp
+++ b/ravenwood/Android.bp
@@ -151,7 +151,7 @@
filegroup {
name: "ravenwood-services-jarjar-rules",
- srcs: ["ravenwood-services-jarjar-rules.txt"],
+ srcs: ["texts/ravenwood-services-jarjar-rules.txt"],
visibility: ["//frameworks/base"],
}
@@ -159,7 +159,7 @@
// The "test" just shows the available stats filenames.
sh_test_host {
name: "ravenwood-stats-checker",
- src: "ravenwood-stats-checker.sh",
+ src: "scripts/ravenwood-stats-checker.sh",
test_suites: ["general-tests"],
data: [
":framework-minus-apex.ravenwood.stats",
diff --git a/ravenwood/ravenwood-stats-checker.sh b/ravenwood/ravenwood-stats-checker.sh
deleted file mode 100755
index fb58e72..0000000
--- a/ravenwood/ravenwood-stats-checker.sh
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/bin/bash
-
-# Just print the available *.csv filenames.
-echo '#Stats files:'
-ls *.csv
\ No newline at end of file
diff --git a/ravenwood/bulk_enable.py b/ravenwood/scripts/bulk_enable.py
similarity index 100%
rename from ravenwood/bulk_enable.py
rename to ravenwood/scripts/bulk_enable.py
diff --git a/ravenwood/fix_test_runner.py b/ravenwood/scripts/fix_test_runner.py
similarity index 100%
rename from ravenwood/fix_test_runner.py
rename to ravenwood/scripts/fix_test_runner.py
diff --git a/ravenwood/list-ravenwood-tests.sh b/ravenwood/scripts/list-ravenwood-tests.sh
similarity index 100%
rename from ravenwood/list-ravenwood-tests.sh
rename to ravenwood/scripts/list-ravenwood-tests.sh
diff --git a/ravenwood/run-ravenwood-tests.sh b/ravenwood/scripts/ravenwood-stats-checker.sh
similarity index 65%
copy from ravenwood/run-ravenwood-tests.sh
copy to ravenwood/scripts/ravenwood-stats-checker.sh
index a303626..93f4a3f 100755
--- a/ravenwood/run-ravenwood-tests.sh
+++ b/ravenwood/scripts/ravenwood-stats-checker.sh
@@ -13,16 +13,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# Run all the ravenwood tests + hoststubgen unit tests.
-
-all_tests="hoststubgentest tiny-framework-dump-test hoststubgen-invoke-test"
-
-# "echo" is to remove the newlines
-all_tests="$all_tests $(echo $(${0%/*}/list-ravenwood-tests.sh) )"
-
-run() {
- echo "Running: $*"
- "${@}"
-}
-
-run ${ATEST:-atest} $all_tests
+# Just print the available *.csv filenames.
+echo '#Stats files:'
+ls *.csv
\ No newline at end of file
diff --git a/ravenwood/scripts/ravenwood-stats-collector.sh b/ravenwood/scripts/ravenwood-stats-collector.sh
new file mode 100755
index 0000000..4dcaa2b
--- /dev/null
+++ b/ravenwood/scripts/ravenwood-stats-collector.sh
@@ -0,0 +1,52 @@
+#!/bin/bash
+# Copyright (C) 2024 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Script to collect the ravenwood "stats" CVS files and create a single file.
+
+set -e
+
+# Output file
+out=/tmp/ravenwood-stats-all.csv
+
+# Where the input files are.
+path=$ANDROID_BUILD_TOP/out/host/linux-x86/testcases/ravenwood-stats-checker/x86_64/
+
+m() {
+ ${ANDROID_BUILD_TOP}/build/soong/soong_ui.bash --make-mode "$@"
+}
+
+# Building this will generate the files we need.
+m ravenwood-stats-checker
+
+# Start...
+
+cd $path
+
+dump() {
+ local jar=$1
+ local file=$2
+
+ sed -e '1d' -e "s/^/$jar,/" $file
+}
+
+collect() {
+ echo 'Jar,PackageName,ClassName,SupportedMethods,TotalMethods'
+ dump "framework-minus-apex" hoststubgen_framework-minus-apex_stats.csv
+ dump "service.core" hoststubgen_services.core_stats.csv
+}
+
+collect >$out
+
+echo "Full dump CVS created at $out"
diff --git a/ravenwood/run-ravenwood-tests.sh b/ravenwood/scripts/run-ravenwood-tests.sh
similarity index 95%
rename from ravenwood/run-ravenwood-tests.sh
rename to ravenwood/scripts/run-ravenwood-tests.sh
index a303626..926c08f 100755
--- a/ravenwood/run-ravenwood-tests.sh
+++ b/ravenwood/scripts/run-ravenwood-tests.sh
@@ -15,7 +15,7 @@
# Run all the ravenwood tests + hoststubgen unit tests.
-all_tests="hoststubgentest tiny-framework-dump-test hoststubgen-invoke-test"
+all_tests="hoststubgentest tiny-framework-dump-test hoststubgen-invoke-test ravenwood-stats-checker"
# "echo" is to remove the newlines
all_tests="$all_tests $(echo $(${0%/*}/list-ravenwood-tests.sh) )"
diff --git a/ravenwood/framework-minus-apex-ravenwood-policies.txt b/ravenwood/texts/framework-minus-apex-ravenwood-policies.txt
similarity index 100%
rename from ravenwood/framework-minus-apex-ravenwood-policies.txt
rename to ravenwood/texts/framework-minus-apex-ravenwood-policies.txt
diff --git a/ravenwood/ravenwood-annotation-allowed-classes.txt b/ravenwood/texts/ravenwood-annotation-allowed-classes.txt
similarity index 100%
rename from ravenwood/ravenwood-annotation-allowed-classes.txt
rename to ravenwood/texts/ravenwood-annotation-allowed-classes.txt
diff --git a/ravenwood/ravenwood-services-jarjar-rules.txt b/ravenwood/texts/ravenwood-services-jarjar-rules.txt
similarity index 100%
rename from ravenwood/ravenwood-services-jarjar-rules.txt
rename to ravenwood/texts/ravenwood-services-jarjar-rules.txt
diff --git a/ravenwood/ravenwood-standard-options.txt b/ravenwood/texts/ravenwood-standard-options.txt
similarity index 100%
rename from ravenwood/ravenwood-standard-options.txt
rename to ravenwood/texts/ravenwood-standard-options.txt
diff --git a/ravenwood/services.core-ravenwood-policies.txt b/ravenwood/texts/services.core-ravenwood-policies.txt
similarity index 100%
rename from ravenwood/services.core-ravenwood-policies.txt
rename to ravenwood/texts/services.core-ravenwood-policies.txt
diff --git a/services/Android.bp b/services/Android.bp
index 7bbb42e..29d1acf 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -254,6 +254,7 @@
required: [
"libukey2_jni_shared",
"protolog.conf.json.gz",
+ "core.protolog.pb",
],
lint: {
baseline_filename: "lint-baseline.xml",
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 5941fd7..47f03f3 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -414,6 +414,7 @@
import com.android.internal.os.BinderCallHeavyHitterWatcher.BinderCallHeavyHitterListener;
import com.android.internal.os.BinderCallHeavyHitterWatcher.HeavyHitterContainer;
import com.android.internal.os.BinderInternal;
+import com.android.internal.os.BinderInternal.BinderProxyCountEventListener;
import com.android.internal.os.BinderTransactionNameResolver;
import com.android.internal.os.ByteTransferPipe;
import com.android.internal.os.IResultReceiver;
@@ -614,8 +615,8 @@
private static final int MINIMUM_MEMORY_GROWTH_THRESHOLD = 10 * 1000; // 10 MB
/**
- * The number of binder proxies we need to have before we start warning and
- * dumping debug info.
+ * The number of binder proxies we need to have before we start dumping debug info
+ * and kill the offenders.
*/
private static final int BINDER_PROXY_HIGH_WATERMARK = 6000;
@@ -625,6 +626,11 @@
*/
private static final int BINDER_PROXY_LOW_WATERMARK = 5500;
+ /**
+ * The number of binder proxies we need to have before we start warning.
+ */
+ private static final int BINDER_PROXY_WARNING_WATERMARK = 5750;
+
// Max character limit for a notification title. If the notification title is larger than this
// the notification will not be legible to the user.
private static final int MAX_BUGREPORT_TITLE_SIZE = 100;
@@ -9063,34 +9069,10 @@
t.traceBegin("setBinderProxies");
BinderInternal.nSetBinderProxyCountWatermarks(BINDER_PROXY_HIGH_WATERMARK,
- BINDER_PROXY_LOW_WATERMARK);
+ BINDER_PROXY_LOW_WATERMARK, BINDER_PROXY_WARNING_WATERMARK);
BinderInternal.nSetBinderProxyCountEnabled(true);
- BinderInternal.setBinderProxyCountCallback(
- (uid) -> {
- Slog.wtf(TAG, "Uid " + uid + " sent too many Binders to uid "
- + Process.myUid());
- BinderProxy.dumpProxyDebugInfo();
- CriticalEventLog.getInstance().logExcessiveBinderCalls(uid);
- if (uid == Process.SYSTEM_UID) {
- Slog.i(TAG, "Skipping kill (uid is SYSTEM)");
- } else {
- killUid(UserHandle.getAppId(uid), UserHandle.getUserId(uid),
- ApplicationExitInfo.REASON_EXCESSIVE_RESOURCE_USAGE,
- ApplicationExitInfo.SUBREASON_EXCESSIVE_BINDER_OBJECTS,
- "Too many Binders sent to SYSTEM");
- // We need to run a GC here, because killing the processes involved
- // actually isn't guaranteed to free up the proxies; in fact, if the
- // GC doesn't run for a long time, we may even exceed the global
- // proxy limit for a process (20000), resulting in system_server itself
- // being killed.
- // Note that the GC here might not actually clean up all the proxies,
- // because the binder reference decrements will come in asynchronously;
- // but if new processes belonging to the UID keep adding proxies, we
- // will get another callback here, and run the GC again - this time
- // cleaning up the old proxies.
- VMRuntime.getRuntime().requestConcurrentGC();
- }
- }, mHandler);
+ BinderInternal.setBinderProxyCountCallback(new MyBinderProxyCountEventListener(),
+ mHandler);
t.traceEnd(); // setBinderProxies
t.traceEnd(); // ActivityManagerStartApps
@@ -9105,6 +9087,46 @@
}
}
+ private class MyBinderProxyCountEventListener implements BinderProxyCountEventListener {
+ @Override
+ public void onLimitReached(int uid) {
+ Slog.wtf(TAG, "Uid " + uid + " sent too many Binders to uid "
+ + Process.myUid());
+ BinderProxy.dumpProxyDebugInfo();
+ CriticalEventLog.getInstance().logExcessiveBinderCalls(uid);
+ if (uid == Process.SYSTEM_UID) {
+ Slog.i(TAG, "Skipping kill (uid is SYSTEM)");
+ } else {
+ killUid(UserHandle.getAppId(uid), UserHandle.getUserId(uid),
+ ApplicationExitInfo.REASON_EXCESSIVE_RESOURCE_USAGE,
+ ApplicationExitInfo.SUBREASON_EXCESSIVE_BINDER_OBJECTS,
+ "Too many Binders sent to SYSTEM");
+ // We need to run a GC here, because killing the processes involved
+ // actually isn't guaranteed to free up the proxies; in fact, if the
+ // GC doesn't run for a long time, we may even exceed the global
+ // proxy limit for a process (20000), resulting in system_server itself
+ // being killed.
+ // Note that the GC here might not actually clean up all the proxies,
+ // because the binder reference decrements will come in asynchronously;
+ // but if new processes belonging to the UID keep adding proxies, we
+ // will get another callback here, and run the GC again - this time
+ // cleaning up the old proxies.
+ VMRuntime.getRuntime().requestConcurrentGC();
+ }
+ }
+
+ @Override
+ public void onWarningThresholdReached(int uid) {
+ if (Flags.logExcessiveBinderProxies()) {
+ Slog.w(TAG, "Uid " + uid + " sent too many ("
+ + BINDER_PROXY_WARNING_WATERMARK + ") Binders to uid " + Process.myUid());
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.EXCESSIVE_BINDER_PROXY_COUNT_REPORTED,
+ uid);
+ }
+ }
+ }
+
private void watchDeviceProvisioning(Context context) {
// setting system property based on whether device is provisioned
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 9c1ce66..5a750c2 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -71,7 +71,7 @@
import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK;
import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE;
import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL;
-import static android.media.audio.Flags.foregroundAudioControl;
+import static android.media.audio.Flags.roForegroundAudioControl;
import static android.os.Process.SCHED_OTHER;
import static android.os.Process.THREAD_GROUP_BACKGROUND;
import static android.os.Process.THREAD_GROUP_DEFAULT;
@@ -2212,7 +2212,7 @@
(fgsType & FOREGROUND_SERVICE_TYPE_LOCATION)
!= 0 ? PROCESS_CAPABILITY_FOREGROUND_LOCATION : 0;
- if (foregroundAudioControl()) { // flag check
+ if (roForegroundAudioControl()) { // flag check
final int fgsAudioType = FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK
| FOREGROUND_SERVICE_TYPE_CAMERA
| FOREGROUND_SERVICE_TYPE_MICROPHONE
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index be47f85..ed58c40 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -34,7 +34,7 @@
import static android.media.audio.Flags.automaticBtDeviceType;
import static android.media.audio.Flags.featureSpatialAudioHeadtrackingLowLatency;
import static android.media.audio.Flags.focusFreezeTestApi;
-import static android.media.audio.Flags.foregroundAudioControl;
+import static android.media.audio.Flags.roForegroundAudioControl;
import static android.media.audiopolicy.Flags.enableFadeManagerConfiguration;
import static android.os.Process.FIRST_APPLICATION_UID;
import static android.os.Process.INVALID_UID;
@@ -4539,10 +4539,11 @@
+ focusFreezeTestApi());
pw.println("\tcom.android.media.audio.disablePrescaleAbsoluteVolume:"
+ disablePrescaleAbsoluteVolume());
+
pw.println("\tcom.android.media.audio.setStreamVolumeOrder:"
+ setStreamVolumeOrder());
- pw.println("\tandroid.media.audio.foregroundAudioControl:"
- + foregroundAudioControl());
+ pw.println("\tandroid.media.audio.roForegroundAudioControl:"
+ + roForegroundAudioControl());
}
private void dumpAudioMode(PrintWriter pw) {
diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java
index 14f3120..7df63b1 100644
--- a/services/core/java/com/android/server/biometrics/AuthService.java
+++ b/services/core/java/com/android/server/biometrics/AuthService.java
@@ -869,9 +869,7 @@
}
if (faceAidlInstances != null && faceAidlInstances.length > 0) {
- mFaceSensorConfigurations.addAidlConfigs(faceAidlInstances,
- name -> IFace.Stub.asInterface(Binder.allowBlocking(
- ServiceManager.waitForDeclaredService(name))));
+ mFaceSensorConfigurations.addAidlConfigs(faceAidlInstances);
}
if (faceService != null) {
@@ -909,9 +907,7 @@
}
if (fingerprintAidlInstances != null && fingerprintAidlInstances.length > 0) {
- mFingerprintSensorConfigurations.addAidlSensors(fingerprintAidlInstances,
- name -> IFingerprint.Stub.asInterface(Binder.allowBlocking(
- ServiceManager.waitForDeclaredService(name))));
+ mFingerprintSensorConfigurations.addAidlSensors(fingerprintAidlInstances);
}
if (fingerprintService != null) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
index 7ee2a7a..1037124 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
@@ -729,8 +729,8 @@
private List<ServiceProvider> getProviders(
FaceSensorConfigurations faceSensorConfigurations) {
final List<ServiceProvider> providers = new ArrayList<>();
- final Pair<String, SensorProps[]> filteredSensorProps =
- filterAvailableHalInstances(faceSensorConfigurations);
+ final Pair<String, SensorProps[]> filteredSensorProps = filterAvailableHalInstances(
+ faceSensorConfigurations);
providers.add(mFaceProviderFunction.getFaceProvider(filteredSensorProps,
faceSensorConfigurations.getResetLockoutRequiresChallenge()));
return providers;
@@ -739,28 +739,36 @@
@NonNull
private Pair<String, SensorProps[]> filterAvailableHalInstances(
FaceSensorConfigurations faceSensorConfigurations) {
- Pair<String, SensorProps[]> finalSensorPair = faceSensorConfigurations.getSensorPair();
+ String finalSensorInstance = faceSensorConfigurations.getSensorInstance();
if (faceSensorConfigurations.isSingleSensorConfigurationPresent()) {
- return finalSensorPair;
+ return new Pair<>(finalSensorInstance,
+ faceSensorConfigurations.getSensorPropForInstance(finalSensorInstance));
}
-
- final Pair<String, SensorProps[]> virtualSensorProps = faceSensorConfigurations
- .getSensorPairForInstance("virtual");
-
- if (Utils.isVirtualEnabled(getContext())) {
- if (virtualSensorProps != null) {
- return virtualSensorProps;
+ final String virtualInstance = "virtual";
+ final boolean isVirtualHalPresent =
+ faceSensorConfigurations.doesInstanceExist(virtualInstance);
+ if (Flags.faceVhalFeature() && Utils.isVirtualEnabled(getContext())) {
+ if (isVirtualHalPresent) {
+ return new Pair<>(virtualInstance,
+ faceSensorConfigurations.getSensorPropForInstance(virtualInstance));
} else {
Slog.e(TAG, "Could not find virtual interface while it is enabled");
- return finalSensorPair;
+ return new Pair<>(finalSensorInstance,
+ faceSensorConfigurations.getSensorPropForInstance(finalSensorInstance));
}
} else {
- if (virtualSensorProps != null) {
- return faceSensorConfigurations.getSensorPairNotForInstance("virtual");
+ if (isVirtualHalPresent) {
+ final String notAVirtualInstance =
+ faceSensorConfigurations.getSensorNameNotForInstance(virtualInstance);
+ if (notAVirtualInstance != null) {
+ return new Pair<>(notAVirtualInstance, faceSensorConfigurations
+ .getSensorPropForInstance(notAVirtualInstance));
+ }
}
}
- return finalSensorPair;
+ return new Pair<>(finalSensorInstance, faceSensorConfigurations
+ .getSensorPropForInstance(finalSensorInstance));
}
private Pair<List<FaceSensorPropertiesInternal>, List<String>>
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index 1ba1213..2dc03ed 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -1128,27 +1128,36 @@
@NonNull
private Pair<String, SensorProps[]> filterAvailableHalInstances(
FingerprintSensorConfigurations fingerprintSensorConfigurations) {
- Pair<String, SensorProps[]> finalSensorPair =
- fingerprintSensorConfigurations.getSensorPair();
+ final String finalSensorInstance = fingerprintSensorConfigurations.getSensorInstance();
if (fingerprintSensorConfigurations.isSingleSensorConfigurationPresent()) {
- return finalSensorPair;
+ return new Pair<>(finalSensorInstance,
+ fingerprintSensorConfigurations.getSensorPropForInstance(finalSensorInstance));
}
-
- final Pair<String, SensorProps[]> virtualSensorPropsPair = fingerprintSensorConfigurations
- .getSensorPairForInstance("virtual");
+ final String virtualInstance = "virtual";
+ final boolean isVirtualHalPresent =
+ fingerprintSensorConfigurations.doesInstanceExist(virtualInstance);
if (Utils.isVirtualEnabled(getContext())) {
- if (virtualSensorPropsPair != null) {
- return virtualSensorPropsPair;
+ if (isVirtualHalPresent) {
+ return new Pair<>(virtualInstance,
+ fingerprintSensorConfigurations.getSensorPropForInstance(virtualInstance));
} else {
Slog.e(TAG, "Could not find virtual interface while it is enabled");
- return finalSensorPair;
+ return new Pair<>(finalSensorInstance,
+ fingerprintSensorConfigurations.getSensorPropForInstance(
+ finalSensorInstance));
}
} else {
- if (virtualSensorPropsPair != null) {
- return fingerprintSensorConfigurations.getSensorPairNotForInstance("virtual");
+ if (isVirtualHalPresent) {
+ final String notAVirtualInstance = fingerprintSensorConfigurations
+ .getSensorNameNotForInstance(virtualInstance);
+ if (notAVirtualInstance != null) {
+ return new Pair<>(notAVirtualInstance, fingerprintSensorConfigurations
+ .getSensorPropForInstance(notAVirtualInstance));
+ }
}
}
- return finalSensorPair;
+ return new Pair<>(finalSensorInstance, fingerprintSensorConfigurations
+ .getSensorPropForInstance(finalSensorInstance));
}
private Pair<List<FingerprintSensorPropertiesInternal>, List<String>>
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index f5ed8d4..9f2c36a 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -93,6 +93,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BackgroundThread;
+import com.android.internal.pm.parsing.pkg.AndroidPackageInternal;
import com.android.internal.pm.pkg.component.ParsedComponent;
import com.android.internal.pm.pkg.component.ParsedIntentInfo;
import com.android.internal.pm.pkg.component.ParsedPermission;
@@ -911,8 +912,10 @@
sharedUserSetting.mDisabledPackages.remove(p);
}
p.getPkgState().setUpdatedSystemApp(false);
+ final AndroidPackageInternal pkg = p.getPkg();
PackageSetting ret = addPackageLPw(name, p.getRealName(), p.getPath(), p.getAppId(),
- p.getFlags(), p.getPrivateFlags(), mDomainVerificationManager.generateNewId());
+ p.getFlags(), p.getPrivateFlags(), mDomainVerificationManager.generateNewId(),
+ pkg == null ? false : pkg.isSdkLibrary());
if (ret != null) {
ret.setLegacyNativeLibraryPath(p.getLegacyNativeLibraryPath());
ret.setPrimaryCpuAbi(p.getPrimaryCpuAbiLegacy());
@@ -951,8 +954,8 @@
}
}
- PackageSetting addPackageLPw(String name, String realName, File codePath, int uid, int pkgFlags,
- int pkgPrivateFlags, @NonNull UUID domainSetId) {
+ PackageSetting addPackageLPw(String name, String realName, File codePath, int uid,
+ int pkgFlags, int pkgPrivateFlags, @NonNull UUID domainSetId, boolean isSdkLibrary) {
PackageSetting p = mPackages.get(name);
if (p != null) {
if (p.getAppId() == uid) {
@@ -964,7 +967,8 @@
}
p = new PackageSetting(name, realName, codePath, pkgFlags, pkgPrivateFlags, domainSetId)
.setAppId(uid);
- if (mAppIds.registerExistingAppId(uid, p, name)) {
+ if ((uid == Process.INVALID_UID && isSdkLibrary && Flags.disallowSdkLibsToBeApps())
+ || mAppIds.registerExistingAppId(uid, p, name)) {
mPackages.put(name, p);
return p;
}
@@ -4176,7 +4180,7 @@
} else if (appId > 0 || (appId == Process.INVALID_UID && isSdkLibrary
&& Flags.disallowSdkLibsToBeApps())) {
packageSetting = addPackageLPw(name.intern(), realName, new File(codePathStr),
- appId, pkgFlags, pkgPrivateFlags, domainSetId);
+ appId, pkgFlags, pkgPrivateFlags, domainSetId, isSdkLibrary);
if (PackageManagerService.DEBUG_SETTINGS)
Log.i(PackageManagerService.TAG, "Reading package " + name + ": appId="
+ appId + " pkg=" + packageSetting);
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index f5ac830..63386a9 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -567,7 +567,7 @@
int autoLockPreference =
Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.PRIVATE_SPACE_AUTO_LOCK,
- Settings.Secure.PRIVATE_SPACE_AUTO_LOCK_NEVER,
+ Settings.Secure.PRIVATE_SPACE_AUTO_LOCK_AFTER_DEVICE_RESTART,
getMainUserIdUnchecked());
Slog.i(LOG_TAG, "Auto-lock settings changed to " + autoLockPreference);
setOrUpdateAutoLockPreferenceForPrivateProfile(autoLockPreference);
@@ -615,7 +615,7 @@
int privateSpaceAutoLockPreference =
Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.PRIVATE_SPACE_AUTO_LOCK,
- Settings.Secure.PRIVATE_SPACE_AUTO_LOCK_NEVER,
+ Settings.Secure.PRIVATE_SPACE_AUTO_LOCK_AFTER_DEVICE_RESTART,
getMainUserIdUnchecked());
if (privateSpaceAutoLockPreference
!= Settings.Secure.PRIVATE_SPACE_AUTO_LOCK_AFTER_INACTIVITY) {
@@ -714,7 +714,7 @@
if (isAutoLockForPrivateSpaceEnabled()) {
int autoLockPreference = Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.PRIVATE_SPACE_AUTO_LOCK,
- Settings.Secure.PRIVATE_SPACE_AUTO_LOCK_NEVER,
+ Settings.Secure.PRIVATE_SPACE_AUTO_LOCK_AFTER_DEVICE_RESTART,
getMainUserIdUnchecked());
boolean isAutoLockOnDeviceLockSelected =
autoLockPreference == Settings.Secure.PRIVATE_SPACE_AUTO_LOCK_ON_DEVICE_LOCK;
@@ -1052,7 +1052,8 @@
setOrUpdateAutoLockPreferenceForPrivateProfile(
Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.PRIVATE_SPACE_AUTO_LOCK,
- Settings.Secure.PRIVATE_SPACE_AUTO_LOCK_NEVER, mainUserId));
+ Settings.Secure.PRIVATE_SPACE_AUTO_LOCK_AFTER_DEVICE_RESTART,
+ mainUserId));
}
}
diff --git a/services/core/java/com/android/server/stats/pull/AggregatedMobileDataStatsPuller.java b/services/core/java/com/android/server/stats/pull/AggregatedMobileDataStatsPuller.java
index 881583a..f28a91c 100644
--- a/services/core/java/com/android/server/stats/pull/AggregatedMobileDataStatsPuller.java
+++ b/services/core/java/com/android/server/stats/pull/AggregatedMobileDataStatsPuller.java
@@ -125,6 +125,11 @@
@GuardedBy("mLock")
private final Map<UidProcState, MobileDataStats> mUidStats;
+ // No reason to keep more dimensions than 3000. The 3000 is the hard top for the statsd metrics
+ // dimensions guardrail. It also will keep the result binder transaction size capped to
+ // approximately 220kB for 3000 atoms
+ private static final int UID_STATS_MAX_SIZE = 3000;
+
private final SparseIntArray mUidPreviousState;
private NetworkStats mLastMobileUidStats = new NetworkStats(0, -1);
@@ -188,14 +193,18 @@
}
final UidProcState statsKey = new UidProcState(uid, previousState);
- MobileDataStats stats;
if (mUidStats.containsKey(statsKey)) {
- stats = mUidStats.get(statsKey);
- } else {
- stats = new MobileDataStats();
- mUidStats.put(statsKey, stats);
+ return mUidStats.get(statsKey);
}
- return stats;
+ if (mUidStats.size() < UID_STATS_MAX_SIZE) {
+ MobileDataStats stats = new MobileDataStats();
+ mUidStats.put(statsKey, stats);
+ return stats;
+ }
+ if (DEBUG) {
+ Slog.w(TAG, "getUidStatsForPreviousStateLocked() UID_STATS_MAX_SIZE reached");
+ }
+ return null;
}
private void noteUidProcessStateImpl(int uid, int state) {
@@ -252,10 +261,12 @@
continue;
}
MobileDataStats stats = getUidStatsForPreviousStateLocked(entry.getUid());
- stats.addTxBytes(entry.getTxBytes());
- stats.addRxBytes(entry.getRxBytes());
- stats.addTxPackets(entry.getTxPackets());
- stats.addRxPackets(entry.getRxPackets());
+ if (stats != null) {
+ stats.addTxBytes(entry.getTxBytes());
+ stats.addRxBytes(entry.getRxBytes());
+ stats.addTxPackets(entry.getTxPackets());
+ stats.addRxPackets(entry.getRxPackets());
+ }
}
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index baf274d..2ec26ca 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -819,12 +819,6 @@
@Nullable
private Rect mLetterboxBoundsForFixedOrientationAndAspectRatio;
- // Bounds populated in resolveAspectRatioRestriction when this activity is letterboxed for
- // aspect ratio. If not null, they are used as parent container in
- // resolveSizeCompatModeConfiguration and in a constructor of CompatDisplayInsets.
- @Nullable
- private Rect mLetterboxBoundsForAspectRatio;
-
// Whether the activity is eligible to be letterboxed for fixed orientation with respect to its
// requested orientation, even when it's letterbox for another reason (e.g., size compat mode)
// and therefore #isLetterboxedForFixedOrientationAndAspectRatio returns false.
@@ -8427,14 +8421,10 @@
fullConfig.windowConfiguration.getRotation());
}
- final Rect letterboxedContainerBounds =
- mLetterboxBoundsForFixedOrientationAndAspectRatio != null
- ? mLetterboxBoundsForFixedOrientationAndAspectRatio
- : mLetterboxBoundsForAspectRatio;
-
// The role of CompatDisplayInsets is like the override bounds.
mCompatDisplayInsets =
- new CompatDisplayInsets(mDisplayContent, this, letterboxedContainerBounds);
+ new CompatDisplayInsets(
+ mDisplayContent, this, mLetterboxBoundsForFixedOrientationAndAspectRatio);
}
private void clearSizeCompatModeAttributes() {
@@ -8506,7 +8496,6 @@
mIsAspectRatioApplied = false;
mIsEligibleForFixedOrientationLetterbox = false;
mLetterboxBoundsForFixedOrientationAndAspectRatio = null;
- mLetterboxBoundsForAspectRatio = null;
// Can't use resolvedConfig.windowConfiguration.getWindowingMode() because it can be
// different from windowing mode of the task (PiP) during transition from fullscreen to PiP
@@ -8545,11 +8534,9 @@
getTaskFragment().computeConfigResourceOverrides(resolvedConfig,
newParentConfiguration);
}
- }
// If activity in fullscreen mode is letterboxed because of fixed orientation then bounds
- // are already calculated in resolveFixedOrientationConfiguration, or if in size compat
- // mode, it should already be calculated in resolveSizeCompatModeConfiguration
- if (!isLetterboxedForFixedOrientationAndAspectRatio() && !mInSizeCompatModeForBounds) {
+ // are already calculated in resolveFixedOrientationConfiguration.
+ } else if (!isLetterboxedForFixedOrientationAndAspectRatio()) {
resolveAspectRatioRestriction(newParentConfiguration);
}
@@ -9043,8 +9030,7 @@
}
final CompatDisplayInsets compatDisplayInsets = getCompatDisplayInsets();
- if (compatDisplayInsets != null
- && !compatDisplayInsets.mIsInFixedOrientationOrAspectRatioLetterbox) {
+ if (compatDisplayInsets != null && !compatDisplayInsets.mIsInFixedOrientationLetterbox) {
// App prefers to keep its original size.
// If the size compat is from previous fixed orientation letterboxing, we may want to
// have fixed orientation letterbox again, otherwise it will show the size compat
@@ -9176,7 +9162,6 @@
// restrict, the bounds should be the requested override bounds.
getTaskFragment().computeConfigResourceOverrides(resolvedConfig, newParentConfiguration,
getFixedRotationTransformDisplayInfo());
- mLetterboxBoundsForAspectRatio = new Rect(resolvedBounds);
}
}
@@ -10741,10 +10726,10 @@
/** Whether the {@link Task} windowingMode represents a floating window*/
final boolean mIsFloating;
/**
- * Whether is letterboxed because of fixed orientation or aspect ratio when the
- * unresizable activity is first shown.
+ * Whether is letterboxed because of fixed orientation when the unresizable activity is
+ * first shown.
*/
- final boolean mIsInFixedOrientationOrAspectRatioLetterbox;
+ final boolean mIsInFixedOrientationLetterbox;
/**
* The nonDecorInsets for each rotation. Includes the navigation bar and cutout insets. It
* is used to compute the appBounds.
@@ -10759,7 +10744,7 @@
/** Constructs the environment to simulate the bounds behavior of the given container. */
CompatDisplayInsets(DisplayContent display, ActivityRecord container,
- @Nullable Rect letterboxedContainerBounds) {
+ @Nullable Rect fixedOrientationBounds) {
mOriginalRotation = display.getRotation();
mIsFloating = container.getWindowConfiguration().tasksAreFloating();
mOriginalRequestedOrientation = container.getRequestedConfigurationOrientation();
@@ -10774,21 +10759,22 @@
mNonDecorInsets[rotation] = emptyRect;
mStableInsets[rotation] = emptyRect;
}
- mIsInFixedOrientationOrAspectRatioLetterbox = false;
+ mIsInFixedOrientationLetterbox = false;
return;
}
final Task task = container.getTask();
- mIsInFixedOrientationOrAspectRatioLetterbox = letterboxedContainerBounds != null;
+ mIsInFixedOrientationLetterbox = fixedOrientationBounds != null;
+
// Store the bounds of the Task for the non-resizable activity to use in size compat
// mode so that the activity will not be resized regardless the windowing mode it is
// currently in.
- // When an activity needs to be letterboxed because of fixed orientation or aspect
- // ratio, use resolved bounds instead of task bounds since the activity will be
- // displayed within these even if it is in size compat mode.
- final Rect filledContainerBounds = mIsInFixedOrientationOrAspectRatioLetterbox
- ? letterboxedContainerBounds
+ // When an activity needs to be letterboxed because of fixed orientation, use fixed
+ // orientation bounds instead of task bounds since the activity will be displayed
+ // within these even if it is in size compat mode.
+ final Rect filledContainerBounds = mIsInFixedOrientationLetterbox
+ ? fixedOrientationBounds
: task != null ? task.getBounds() : display.getBounds();
final int filledContainerRotation = task != null
? task.getConfiguration().windowConfiguration.getRotation()
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 38f0587a..354cab3 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -2160,19 +2160,6 @@
return rect;
}
- @Override
- public ActivityManager.TaskDescription getTaskDescription(int id) {
- synchronized (mGlobalLock) {
- enforceTaskPermission("getTaskDescription()");
- final Task tr = mRootWindowContainer.anyTaskForId(id,
- MATCH_ATTACHED_TASK_OR_RECENT_TASKS);
- if (tr != null) {
- return tr.getTaskDescription();
- }
- }
- return null;
- }
-
/**
* Sets the locusId for a particular activity.
*
@@ -3072,8 +3059,33 @@
@Override
public Bitmap getTaskDescriptionIcon(String filePath, int userId) {
- userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
- userId, "getTaskDescriptionIcon");
+ final int callingUid = Binder.getCallingUid();
+ // Verify that the caller can make the request for the given userId
+ userId = handleIncomingUser(Binder.getCallingPid(), callingUid, userId,
+ "getTaskDescriptionIcon");
+ synchronized (mGlobalLock) {
+ // Verify that the caller can make the request for given icon file path
+ final ActivityRecord matchingActivity = mRootWindowContainer.getActivity(
+ r -> {
+ if (r.taskDescription == null
+ || r.taskDescription.getIconFilename() == null) {
+ return false;
+ }
+ return r.taskDescription.getIconFilename().equals(filePath);
+ });
+ if (matchingActivity == null || (matchingActivity.getUid() != callingUid)) {
+ // Caller UID doesn't match the requested Activity's UID, check if caller is
+ // privileged
+ try {
+ enforceActivityTaskPermission("getTaskDescriptionIcon");
+ } catch (SecurityException e) {
+ Slog.w(TAG, "getTaskDescriptionIcon(): request (callingUid=" + callingUid
+ + ", filePath=" + filePath + ", user=" + userId + ") doesn't match any "
+ + "activity");
+ throw e;
+ }
+ }
+ }
final File passedIconFile = new File(filePath);
final File legitIconFile = new File(TaskPersister.getUserImagesDir(userId),
@@ -3303,6 +3315,13 @@
return false;
}
+ /**
+ * An instance method that's easier for mocking in tests.
+ */
+ void enforceActivityTaskPermission(String func) {
+ enforceTaskPermission(func);
+ }
+
static void enforceTaskPermission(String func) {
if (checkCallingPermission(MANAGE_ACTIVITY_TASKS) == PackageManager.PERMISSION_GRANTED) {
return;
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 6f1c834..1ce2cd8 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -1277,8 +1277,9 @@
final ActivityRecord top = topRunningActivity();
final ActivityRecord resumedActivity = getResumedActivity();
if (resumedActivity != null
- && (top.getTaskFragment() != this || !canBeResumed(resuming))) {
- // Pausing the resumed activity because it is occluded by other task fragment.
+ && (top == null || top.getTaskFragment() != this || !canBeResumed(resuming))) {
+ // Pausing the resumed activity because it is occluded by other task fragment, or
+ // should not be remained in resumed state.
if (startPausing(false /* uiSleeping*/, resuming, reason)) {
someActivityPaused[0]++;
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
index 538c0ee..c9aab53 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
@@ -166,7 +166,7 @@
null
}
whenever(mocks.settings.addPackageLPw(nullable(), nullable(), nullable(), nullable(),
- nullable(), nullable(), nullable())) {
+ nullable(), nullable(), nullable(), nullable())) {
val name: String = getArgument(0)
val pendingAdd = mPendingPackageAdds.firstOrNull { it.first == name }
?: return@whenever null
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java
index 6aa1825..759a974 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java
@@ -736,9 +736,10 @@
Mockito.clearInvocations(mKeyguardManager);
Mockito.clearInvocations(mSpiedContext);
- // Finally, set the preference to don't auto-lock
+ // Finally, set the preference to auto-lock only after device restart, which is the default
+ // behaviour
mUms.setOrUpdateAutoLockPreferenceForPrivateProfile(
- Settings.Secure.PRIVATE_SPACE_AUTO_LOCK_NEVER);
+ Settings.Secure.PRIVATE_SPACE_AUTO_LOCK_AFTER_DEVICE_RESTART);
// Verify that inactivity broadcasts are unregistered and keyguard listener was removed
Mockito.verify(mSpiedContext).unregisterReceiver(any());
diff --git a/services/tests/servicestests/src/com/android/server/audio/VolumeHelperTest.java b/services/tests/servicestests/src/com/android/server/audio/VolumeHelperTest.java
index 83bbd0e..23728db 100644
--- a/services/tests/servicestests/src/com/android/server/audio/VolumeHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/audio/VolumeHelperTest.java
@@ -35,6 +35,7 @@
import static android.media.AudioManager.STREAM_RING;
import static android.media.AudioManager.STREAM_SYSTEM;
import static android.media.AudioManager.STREAM_VOICE_CALL;
+import static android.media.audio.Flags.autoPublicVolumeApiHardening;
import static android.view.KeyEvent.ACTION_DOWN;
import static android.view.KeyEvent.KEYCODE_VOLUME_UP;
@@ -47,6 +48,7 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeNotNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -66,6 +68,8 @@
import android.annotation.Nullable;
import android.app.AppOpsManager;
import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
import android.media.AudioDeviceAttributes;
import android.media.AudioDeviceInfo;
import android.media.AudioManager;
@@ -214,6 +218,19 @@
reset(mSpyAudioSystem);
+ final boolean useFixedVolume = mContext.getResources().getBoolean(
+ Resources.getSystem().getIdentifier("config_useFixedVolume", "bool", "android"));
+ final PackageManager packageManager = mContext.getPackageManager();
+ final boolean isTelevision = packageManager != null
+ && (packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)
+ || packageManager.hasSystemFeature(PackageManager.FEATURE_TELEVISION));
+ final boolean isSingleVolume = mContext.getResources().getBoolean(
+ Resources.getSystem().getIdentifier("config_single_volume", "bool", "android"));
+ final boolean automotiveHardened = mContext.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_AUTOMOTIVE) && autoPublicVolumeApiHardening();
+ assumeFalse("Skipping test for fixed, TV, single volume and auto devices",
+ useFixedVolume || isTelevision || isSingleVolume || automotiveHardened);
+
InstrumentationRegistry.getInstrumentation().getUiAutomation()
.adoptShellPermissionIdentity(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED,
Manifest.permission.MODIFY_AUDIO_ROUTING,
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
index f0dc5f0..7e04277 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
@@ -269,7 +269,7 @@
mFingerprintSensorConfigurationsCaptor.capture());
final SensorProps[] fingerprintProp = mFingerprintSensorConfigurationsCaptor.getValue()
- .getSensorPairForInstance("defaultHIDL").second;
+ .getSensorPropForInstance("defaultHIDL");
assertEquals(fingerprintProp[0].commonProps.sensorId, fingerprintId);
assertEquals(fingerprintProp[0].commonProps.sensorStrength,
@@ -280,7 +280,7 @@
final android.hardware.biometrics.face.SensorProps[] faceProp =
mFaceSensorConfigurationsCaptor.getValue()
- .getSensorPairForInstance("defaultHIDL").second;
+ .getSensorPropForInstance("defaultHIDL");
assertEquals(faceProp[0].commonProps.sensorId, faceId);
assertEquals(faceProp[0].commonProps.sensorStrength,
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/FaceServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/FaceServiceTest.java
index 3aaac2e..e015e97 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/FaceServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/FaceServiceTest.java
@@ -32,8 +32,6 @@
import android.content.pm.PackageManager;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.IBiometricService;
-import android.hardware.biometrics.face.IFace;
-import android.hardware.biometrics.face.SensorProps;
import android.hardware.face.FaceAuthenticateOptions;
import android.hardware.face.FaceSensorConfigurations;
import android.hardware.face.FaceSensorPropertiesInternal;
@@ -93,18 +91,12 @@
@Mock
private FaceProvider mFaceProviderVirtual;
@Mock
- private IFace mDefaultFaceDaemon;
- @Mock
- private IFace mVirtualFaceDaemon;
- @Mock
private IBiometricService mIBiometricService;
@Mock
private IBinder mToken;
@Mock
private IFaceServiceReceiver mFaceServiceReceiver;
- private final SensorProps mDefaultSensorProps = new SensorProps();
- private final SensorProps mVirtualSensorProps = new SensorProps();
private FaceService mFaceService;
private final FaceSensorPropertiesInternal mSensorPropsDefault =
new FaceSensorPropertiesInternal(ID_DEFAULT, STRENGTH_STRONG,
@@ -126,10 +118,6 @@
@Before
public void setUp() throws RemoteException {
- when(mDefaultFaceDaemon.getSensorProps()).thenReturn(
- new SensorProps[]{mDefaultSensorProps});
- when(mVirtualFaceDaemon.getSensorProps()).thenReturn(
- new SensorProps[]{mVirtualSensorProps});
when(mFaceProviderDefault.getSensorProperties()).thenReturn(List.of(mSensorPropsDefault));
when(mFaceProviderVirtual.getSensorProperties()).thenReturn(List.of(mSensorPropsVirtual));
when(mFaceProviderDefault.containsSensor(anyInt()))
@@ -140,15 +128,7 @@
mContext.getTestablePermissions().setPermission(
USE_BIOMETRIC_INTERNAL, PackageManager.PERMISSION_GRANTED);
mFaceSensorConfigurations = new FaceSensorConfigurations(false);
- mFaceSensorConfigurations.addAidlConfigs(new String[]{NAME_DEFAULT, NAME_VIRTUAL},
- (name) -> {
- if (name.equals(IFace.DESCRIPTOR + "/" + NAME_DEFAULT)) {
- return mDefaultFaceDaemon;
- } else if (name.equals(IFace.DESCRIPTOR + "/" + NAME_VIRTUAL)) {
- return mVirtualFaceDaemon;
- }
- return null;
- });
+ mFaceSensorConfigurations.addAidlConfigs(new String[]{NAME_DEFAULT, NAME_VIRTUAL});
}
private void initService() {
@@ -199,15 +179,7 @@
@RequiresFlagsEnabled(Flags.FLAG_DE_HIDL)
public void registerAuthenticatorsLegacy_virtualAlwaysWhenNoOther() throws Exception {
mFaceSensorConfigurations = new FaceSensorConfigurations(false);
- mFaceSensorConfigurations.addAidlConfigs(new String[]{NAME_VIRTUAL},
- (name) -> {
- if (name.equals(IFace.DESCRIPTOR + "/" + NAME_DEFAULT)) {
- return mDefaultFaceDaemon;
- } else if (name.equals(IFace.DESCRIPTOR + "/" + NAME_VIRTUAL)) {
- return mVirtualFaceDaemon;
- }
- return null;
- });
+ mFaceSensorConfigurations.addAidlConfigs(new String[]{NAME_VIRTUAL});
initService();
mFaceService.mServiceWrapper.registerAuthenticatorsLegacy(mFaceSensorConfigurations);
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceTest.java
index 88956b6..20961a9 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceTest.java
@@ -43,8 +43,6 @@
import android.content.ComponentName;
import android.content.pm.PackageManager;
import android.hardware.biometrics.IBiometricService;
-import android.hardware.biometrics.fingerprint.IFingerprint;
-import android.hardware.biometrics.fingerprint.SensorProps;
import android.hardware.fingerprint.FingerprintAuthenticateOptions;
import android.hardware.fingerprint.FingerprintSensorConfigurations;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
@@ -123,10 +121,6 @@
private IBinder mToken;
@Mock
private VirtualDeviceManagerInternal mVdmInternal;
- @Mock
- private IFingerprint mDefaultFingerprintDaemon;
- @Mock
- private IFingerprint mVirtualFingerprintDaemon;
@Captor
private ArgumentCaptor<FingerprintAuthenticateOptions> mAuthenticateOptionsCaptor;
@@ -145,8 +139,6 @@
false /* resetLockoutRequiresHardwareAuthToken */);
private FingerprintSensorConfigurations mFingerprintSensorConfigurations;
private FingerprintService mService;
- private final SensorProps mDefaultSensorProps = new SensorProps();
- private final SensorProps mVirtualSensorProps = new SensorProps();
@Before
public void setup() throws Exception {
@@ -159,10 +151,6 @@
.thenAnswer(i -> i.getArguments()[0].equals(ID_DEFAULT));
when(mFingerprintVirtual.containsSensor(anyInt()))
.thenAnswer(i -> i.getArguments()[0].equals(ID_VIRTUAL));
- when(mDefaultFingerprintDaemon.getSensorProps()).thenReturn(
- new SensorProps[]{mDefaultSensorProps});
- when(mVirtualFingerprintDaemon.getSensorProps()).thenReturn(
- new SensorProps[]{mVirtualSensorProps});
mContext.addMockSystemService(AppOpsManager.class, mAppOpsManager);
for (int permission : List.of(OP_USE_BIOMETRIC, OP_USE_FINGERPRINT)) {
@@ -177,15 +165,7 @@
mFingerprintSensorConfigurations = new FingerprintSensorConfigurations(
true /* resetLockoutRequiresHardwareAuthToken */);
- mFingerprintSensorConfigurations.addAidlSensors(new String[]{NAME_DEFAULT, NAME_VIRTUAL},
- (name) -> {
- if (name.equals(IFingerprint.DESCRIPTOR + "/" + NAME_DEFAULT)) {
- return mDefaultFingerprintDaemon;
- } else if (name.equals(IFingerprint.DESCRIPTOR + "/" + NAME_VIRTUAL)) {
- return mVirtualFingerprintDaemon;
- }
- return null;
- });
+ mFingerprintSensorConfigurations.addAidlSensors(new String[]{NAME_DEFAULT, NAME_VIRTUAL});
}
private void initServiceWith(String... aidlInstances) {
@@ -270,15 +250,7 @@
public void registerAuthenticatorsLegacy_virtualAlwaysWhenNoOther() throws Exception {
mFingerprintSensorConfigurations =
new FingerprintSensorConfigurations(true);
- mFingerprintSensorConfigurations.addAidlSensors(new String[]{NAME_VIRTUAL},
- (name) -> {
- if (name.equals(IFingerprint.DESCRIPTOR + "/" + NAME_DEFAULT)) {
- return mDefaultFingerprintDaemon;
- } else if (name.equals(IFingerprint.DESCRIPTOR + "/" + NAME_VIRTUAL)) {
- return mVirtualFingerprintDaemon;
- }
- return null;
- });
+ mFingerprintSensorConfigurations.addAidlSensors(new String[]{NAME_VIRTUAL});
initServiceWith(NAME_VIRTUAL);
mService.mServiceWrapper.registerAuthenticatorsLegacy(mFingerprintSensorConfigurations);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 173a1b6..1355092 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -1634,6 +1634,28 @@
assertThat(transition.isInTransientHide(top.getTask())).isTrue();
}
+ /**
+ * Tests ATMS#startActivityWithScreenshot should collect display content for creating snapshot.
+ */
+ @Test
+ public void testActivityStartWithScreenshot() {
+ final ActivityStarter starter = prepareStarter(0 /* flags */);
+ starter.setFreezeScreen(true);
+
+ registerTestTransitionPlayer();
+
+ final Intent intent = new Intent();
+ intent.setComponent(ActivityBuilder.getDefaultComponent());
+ starter.setReason("testActivityStartWithScreenshot")
+ .setIntent(intent)
+ .execute();
+
+ final TransitionController controller = mRootWindowContainer.mTransitionController;
+ final Transition transition = controller.getCollectingTransition();
+ final Transition.ChangeInfo targetChangeInfo = transition.mChanges.get(mDisplayContent);
+ assertThat(targetChangeInfo).isNotNull();
+ }
+
@Test
public void testActivityStart_expectAddedToRecentTask() {
RecentTasks recentTasks = mock(RecentTasks.class);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
index ed99108..400f9bb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
@@ -38,18 +38,22 @@
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.never;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityManager;
+import android.app.ActivityManager.TaskDescription;
import android.app.IApplicationThread;
import android.app.PictureInPictureParams;
import android.app.servertransaction.ClientTransactionItem;
@@ -62,6 +66,7 @@
import android.os.LocaleList;
import android.os.PowerManagerInternal;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
import android.view.Display;
import android.view.DisplayInfo;
@@ -1099,4 +1104,61 @@
verify(mClientLifecycleManager).onLayoutContinued();
}
+
+ @Test
+ public void testGetTaskDescriptionIcon_matchingUid() {
+ // Ensure that we do not hold MANAGE_ACTIVITY_TASKS
+ doThrow(new SecurityException()).when(mAtm).enforceActivityTaskPermission(any());
+
+ final String filePath = "abc/def";
+ // Create an activity with a task description at the test icon filepath
+ final ActivityRecord activity = new ActivityBuilder(mAtm)
+ .setUid(android.os.Process.myUid())
+ .setCreateTask(true)
+ .build();
+ final TaskDescription td = new TaskDescription.Builder().build();
+ td.setIconFilename(filePath);
+ activity.setTaskDescription(td);
+
+ // Verify this calls and does not throw a security exception
+ try {
+ mAtm.getTaskDescriptionIcon(filePath, activity.mUserId);
+ } catch (SecurityException e) {
+ fail("Unexpected security exception: " + e);
+ } catch (IllegalArgumentException e) {
+ // Ok, the file doesn't actually exist
+ }
+ }
+
+ @Test
+ public void testGetTaskDescriptionIcon_noMatchingActivity_expectException() {
+ // Ensure that we do not hold MANAGE_ACTIVITY_TASKS
+ doThrow(new SecurityException()).when(mAtm).enforceActivityTaskPermission(any());
+
+ final String filePath = "abc/def";
+
+ // Verify this throws a security exception due to no matching activity
+ assertThrows(SecurityException.class,
+ () -> mAtm.getTaskDescriptionIcon(filePath, UserHandle.myUserId()));
+ }
+
+ @Test
+ public void testGetTaskDescriptionIcon_noMatchingUid_expectException() {
+ // Ensure that we do not hold MANAGE_ACTIVITY_TASKS
+ doThrow(new SecurityException()).when(mAtm).enforceActivityTaskPermission(any());
+
+ final String filePath = "abc/def";
+ // Create an activity with a task description at the test icon filepath
+ final ActivityRecord activity = new ActivityBuilder(mAtm)
+ .setCreateTask(true)
+ .setUid(101010)
+ .build();
+ final TaskDescription td = new TaskDescription.Builder().build();
+ td.setIconFilename(filePath);
+ activity.setTaskDescription(td);
+
+ // Verify this throws a security exception due to no matching UID
+ assertThrows(SecurityException.class,
+ () -> mAtm.getTaskDescriptionIcon(filePath, activity.mUserId));
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index bfa191e..75b84d1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -1472,7 +1472,6 @@
assertSecurityException(expectCallable, () -> mAtm.registerTaskStackListener(null));
assertSecurityException(expectCallable,
() -> mAtm.unregisterTaskStackListener(null));
- assertSecurityException(expectCallable, () -> mAtm.getTaskDescription(0));
assertSecurityException(expectCallable, () -> mAtm.cancelTaskWindowTransition(0));
assertSecurityException(expectCallable, () -> mAtm.startRecentsActivity(null, 0,
null));
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 680738b..856ad2a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -27,7 +27,6 @@
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_16_9;
import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_3_2;
@@ -1943,7 +1942,8 @@
assertThat(mActivity.inSizeCompatMode()).isTrue();
assertActivityMaxBoundsSandboxed();
- final int scale = dh / dw;
+
+ final int scale = dh / dw;
// App bounds should be dh / scale x dw / scale
assertEquals(dw, rotatedDisplayBounds.width());
@@ -4148,37 +4148,6 @@
}
@Test
- public void testFixedAspectRatioAppInPortraitCloseToSquareDisplay_notInSizeCompat() {
- setUpDisplaySizeWithApp(2200, 2280);
- mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
- final DisplayContent display = mActivity.mDisplayContent;
- // Simulate taskbar, final app bounds are (0, 0, 2200, 2130) - landscape
- final WindowState navbar = createWindow(null, TYPE_NAVIGATION_BAR, mDisplayContent,
- "navbar");
- final Binder owner = new Binder();
- navbar.mAttrs.providedInsets = new InsetsFrameProvider[] {
- new InsetsFrameProvider(owner, 0, WindowInsets.Type.navigationBars())
- .setInsetsSize(Insets.of(0, 0, 0, 150))
- };
- display.getDisplayPolicy().addWindowLw(navbar, navbar.mAttrs);
- assertTrue(navbar.providesDisplayDecorInsets()
- && display.getDisplayPolicy().updateDecorInsetsInfo());
- display.sendNewConfiguration();
-
- prepareMinAspectRatio(mActivity, OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE,
- SCREEN_ORIENTATION_LANDSCAPE);
- // To force config to update again but with the same landscape orientation.
- mActivity.setRequestedOrientation(SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
-
- assertTrue(mActivity.shouldCreateCompatDisplayInsets());
- assertNotNull(mActivity.getCompatDisplayInsets());
- // Activity is not letterboxed for fixed orientation because orientation is respected
- // with insets, and should not be in size compat mode
- assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
- assertFalse(mActivity.inSizeCompatMode());
- }
-
- @Test
public void testApplyAspectRatio_activityAlignWithParentAppVertical() {
if (Flags.insetsDecoupledConfiguration()) {
// TODO (b/151861875): Re-enable it. This is disabled temporarily because the config
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index dab966b..1ca808f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -833,7 +833,7 @@
final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task).build();
final ActivityRecord.CompatDisplayInsets compatInsets =
new ActivityRecord.CompatDisplayInsets(
- display, activity, /* letterboxedContainerBounds */ null);
+ display, activity, /* fixedOrientationBounds= */ null);
task.computeConfigResourceOverrides(inOutConfig, parentConfig, compatInsets);
assertEquals(largerLandscapeBounds, inOutConfig.windowConfiguration.getAppBounds());