Merge "Make SystemBarUtils injectable + Kosmos fixtures" into main
diff --git a/OWNERS b/OWNERS
index 023bdef..733157f 100644
--- a/OWNERS
+++ b/OWNERS
@@ -37,3 +37,5 @@
per-file *ravenwood* = file:ravenwood/OWNERS
per-file *Ravenwood* = file:ravenwood/OWNERS
+
+per-file PERFORMANCE_OWNERS = file:/PERFORMANCE_OWNERS
diff --git a/PERFORMANCE_OWNERS b/PERFORMANCE_OWNERS
index 9452ea3..48a0201 100644
--- a/PERFORMANCE_OWNERS
+++ b/PERFORMANCE_OWNERS
@@ -3,3 +3,6 @@
dualli@google.com
carmenjackson@google.com
philipcuadra@google.com
+shayba@google.com
+jdduke@google.com
+shombert@google.com
diff --git a/core/api/current.txt b/core/api/current.txt
index 7206298..a761674 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -4516,7 +4516,7 @@
method @NonNull public final <T extends android.view.View> T requireViewById(@IdRes int);
method public final void runOnUiThread(Runnable);
method public void setActionBar(@Nullable android.widget.Toolbar);
- method public void setAllowCrossUidActivitySwitchFromBelow(boolean);
+ method @FlaggedApi("android.security.asm_restrictions_enabled") public void setAllowCrossUidActivitySwitchFromBelow(boolean);
method public void setContentTransitionManager(android.transition.TransitionManager);
method public void setContentView(@LayoutRes int);
method public void setContentView(android.view.View);
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index a1465df..9b11b50 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -4089,7 +4089,8 @@
field @Deprecated public static final int INTENT_FILTER_VERIFICATION_SUCCESS = 1; // 0x1
field @Deprecated public static final int MASK_PERMISSION_FLAGS = 255; // 0xff
field public static final int MATCH_ANY_USER = 4194304; // 0x400000
- field public static final int MATCH_CLONE_PROFILE = 536870912; // 0x20000000
+ field @Deprecated public static final int MATCH_CLONE_PROFILE = 536870912; // 0x20000000
+ field @FlaggedApi("android.content.pm.fix_duplicated_flags") public static final long MATCH_CLONE_PROFILE_LONG = 17179869184L; // 0x400000000L
field public static final int MATCH_FACTORY_ONLY = 2097152; // 0x200000
field public static final int MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS = 536870912; // 0x20000000
field public static final int MATCH_INSTANT = 8388608; // 0x800000
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 98a78cf..7417137 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -259,6 +259,7 @@
field public static final String OPSTR_ACTIVITY_RECOGNITION_SOURCE = "android:activity_recognition_source";
field public static final String OPSTR_MANAGE_ONGOING_CALLS = "android:manage_ongoing_calls";
field public static final String OPSTR_RECORD_AUDIO_HOTWORD = "android:record_audio_hotword";
+ field public static final String OPSTR_RESERVED_FOR_TESTING = "android:reserved_for_testing";
field public static final String OPSTR_USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER = "android:use_icc_auth_with_device_identifier";
field public static final int OP_COARSE_LOCATION = 0; // 0x0
field public static final int OP_RECORD_AUDIO = 27; // 0x1b
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index c52d27ea..cb08dad 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -9387,6 +9387,7 @@
* @param allowed {@code true} to disable the UID restrictions; {@code false} to revert back to
* the default behaviour
*/
+ @FlaggedApi(android.security.Flags.FLAG_ASM_RESTRICTIONS_ENABLED)
public void setAllowCrossUidActivitySwitchFromBelow(boolean allowed) {
ActivityClient.getInstance().setAllowCrossUidActivitySwitchFromBelow(mToken, allowed);
}
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 71fe47e..ec43184 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -16,8 +16,8 @@
package android.app;
-import static android.view.contentprotection.flags.Flags.FLAG_CREATE_ACCESSIBILITY_OVERLAY_APP_OP_ENABLED;
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 java.lang.Long.max;
@@ -1521,9 +1521,17 @@
*/
public static final int OP_MEDIA_ROUTING_CONTROL = AppProtoEnums.APP_OP_MEDIA_ROUTING_CONTROL;
+ /**
+ * Op code for use by tests to avoid interfering history logs that the wider system might
+ * trigger.
+ *
+ * @hide
+ */
+ public static final int OP_RESERVED_FOR_TESTING = AppProtoEnums.APP_OP_RESERVED_FOR_TESTING;
+
/** @hide */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static final int _NUM_OP = 141;
+ public static final int _NUM_OP = 142;
/**
* All app ops represented as strings.
@@ -1671,6 +1679,7 @@
OPSTR_CREATE_ACCESSIBILITY_OVERLAY,
OPSTR_MEDIA_ROUTING_CONTROL,
OPSTR_ENABLE_MOBILE_DATA_BY_USER,
+ OPSTR_RESERVED_FOR_TESTING,
})
public @interface AppOpString {}
@@ -2330,6 +2339,17 @@
public static final String OPSTR_ENABLE_MOBILE_DATA_BY_USER =
"android:enable_mobile_data_by_user";
+ /**
+ * Reserved for use by appop tests so that operations done legitimately by the platform don't
+ * interfere with expected results. Platform code should never use this.
+ *
+ * @hide
+ */
+ @TestApi
+ @SuppressLint("UnflaggedApi")
+ public static final String OPSTR_RESERVED_FOR_TESTING =
+ "android:reserved_for_testing";
+
/** {@link #sAppOpsToNote} not initialized yet for this op */
private static final byte SHOULD_COLLECT_NOTE_OP_NOT_INITIALIZED = 0;
/** Should not collect noting of this app-op in {@link #sAppOpsToNote} */
@@ -2887,6 +2907,8 @@
.setPermission(Manifest.permission.MEDIA_ROUTING_CONTROL).build(),
new AppOpInfo.Builder(OP_ENABLE_MOBILE_DATA_BY_USER, OPSTR_ENABLE_MOBILE_DATA_BY_USER,
"ENABLE_MOBILE_DATA_BY_USER").setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_RESERVED_FOR_TESTING, OPSTR_RESERVED_FOR_TESTING,
+ "OP_RESERVED_FOR_TESTING").setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
};
// The number of longs needed to form a full bitmask of app ops
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index c86ccfd..c7a75ed 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -117,6 +117,7 @@
* developer guide.</p>
* </div>
*/
+@android.ravenwood.annotation.RavenwoodKeepPartialClass
public abstract class ContentProvider implements ContentInterface, ComponentCallbacks2 {
private static final String TAG = "ContentProvider";
@@ -2781,6 +2782,7 @@
}
/** @hide */
+ @android.ravenwood.annotation.RavenwoodKeep
private Uri maybeGetUriWithoutUserId(Uri uri) {
if (mSingleUser) {
return uri;
@@ -2789,6 +2791,7 @@
}
/** @hide */
+ @android.ravenwood.annotation.RavenwoodKeep
public static int getUserIdFromAuthority(String auth, int defaultUserId) {
if (auth == null) return defaultUserId;
int end = auth.lastIndexOf('@');
@@ -2803,17 +2806,20 @@
}
/** @hide */
+ @android.ravenwood.annotation.RavenwoodKeep
public static int getUserIdFromAuthority(String auth) {
return getUserIdFromAuthority(auth, UserHandle.USER_CURRENT);
}
/** @hide */
+ @android.ravenwood.annotation.RavenwoodKeep
public static int getUserIdFromUri(Uri uri, int defaultUserId) {
if (uri == null) return defaultUserId;
return getUserIdFromAuthority(uri.getAuthority(), defaultUserId);
}
/** @hide */
+ @android.ravenwood.annotation.RavenwoodKeep
public static int getUserIdFromUri(Uri uri) {
return getUserIdFromUri(uri, UserHandle.USER_CURRENT);
}
@@ -2824,6 +2830,7 @@
* @hide
*/
@TestApi
+ @android.ravenwood.annotation.RavenwoodKeep
public @NonNull static UserHandle getUserHandleFromUri(@NonNull Uri uri) {
return UserHandle.of(getUserIdFromUri(uri, Process.myUserHandle().getIdentifier()));
}
@@ -2834,6 +2841,7 @@
* If there is no userId in the authority, it symply returns the argument
* @hide
*/
+ @android.ravenwood.annotation.RavenwoodKeep
public static String getAuthorityWithoutUserId(String auth) {
if (auth == null) return null;
int end = auth.lastIndexOf('@');
@@ -2841,6 +2849,7 @@
}
/** @hide */
+ @android.ravenwood.annotation.RavenwoodKeep
public static Uri getUriWithoutUserId(Uri uri) {
if (uri == null) return null;
Uri.Builder builder = uri.buildUpon();
@@ -2849,6 +2858,7 @@
}
/** @hide */
+ @android.ravenwood.annotation.RavenwoodKeep
public static boolean uriHasUserId(Uri uri) {
if (uri == null) return false;
return !TextUtils.isEmpty(uri.getUserInfo());
@@ -2872,6 +2882,7 @@
*/
@NonNull
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @android.ravenwood.annotation.RavenwoodKeep
public static Uri createContentUriForUser(
@NonNull Uri contentUri, @NonNull UserHandle userHandle) {
if (!ContentResolver.SCHEME_CONTENT.equals(contentUri.getScheme())) {
@@ -2898,6 +2909,7 @@
/** @hide */
@UnsupportedAppUsage
+ @android.ravenwood.annotation.RavenwoodKeep
public static Uri maybeAddUserId(Uri uri, int userId) {
if (uri == null) return null;
if (userId != UserHandle.USER_CURRENT
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 607e904..f865a36 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -919,6 +919,10 @@
@Retention(RetentionPolicy.SOURCE)
public @interface InstrumentationInfoFlags {}
+ //-------------------------------------------------------------------------
+ // Beginning of GET_ and MATCH_ flags
+ //-------------------------------------------------------------------------
+
/**
* {@link PackageInfo} flag: return information about
* activities in the package in {@link PackageInfo#activities}.
@@ -1216,30 +1220,21 @@
*/
public static final int MATCH_DIRECT_BOOT_AUTO = 0x10000000;
- /**
- * {@link ResolveInfo} flag: allow matching components across clone profile
- * <p>
- * This flag is used only for query and not resolution, the default behaviour would be to
- * restrict querying across clone profile. This flag would be honored only if caller have
- * permission {@link Manifest.permission.QUERY_CLONED_APPS}.
- *
- * @hide
- * <p>
- */
- @SystemApi
- public static final int MATCH_CLONE_PROFILE = 0x20000000;
-
- /**
- * @deprecated Use {@link #GET_ATTRIBUTIONS_LONG} to avoid unintended sign extension.
- */
- @Deprecated
- public static final int GET_ATTRIBUTIONS = 0x80000000;
-
/** @hide */
@Deprecated
public static final int MATCH_DEBUG_TRIAGED_MISSING = MATCH_DIRECT_BOOT_AUTO;
/**
+ * @deprecated Use {@link #MATCH_CLONE_PROFILE_LONG} instead.
+ *
+ * @hide
+ */
+ @SuppressLint("UnflaggedApi") // Just adding the @Deprecated annotation
+ @Deprecated
+ @SystemApi
+ public static final int MATCH_CLONE_PROFILE = 0x20000000;
+
+ /**
* {@link PackageInfo} flag: include system apps that are in the uninstalled state and have
* been set to be hidden until installed via {@link #setSystemAppState}.
* @hide
@@ -1257,6 +1252,12 @@
public static final int MATCH_APEX = 0x40000000;
/**
+ * @deprecated Use {@link #GET_ATTRIBUTIONS_LONG} to avoid unintended sign extension.
+ */
+ @Deprecated
+ public static final int GET_ATTRIBUTIONS = 0x80000000;
+
+ /**
* {@link PackageInfo} flag: return all attributions declared in the package manifest
*/
public static final long GET_ATTRIBUTIONS_LONG = 0x80000000L;
@@ -1282,6 +1283,23 @@
public static final long MATCH_QUARANTINED_COMPONENTS = 1L << 33;
/**
+ * {@link ResolveInfo} flag: allow matching components across clone profile
+ * <p>
+ * This flag is used only for query and not resolution, the default behaviour would be to
+ * restrict querying across clone profile. This flag would be honored only if caller have
+ * permission {@link Manifest.permission.QUERY_CLONED_APPS}.
+ *
+ * @hide
+ */
+ @FlaggedApi(android.content.pm.Flags.FLAG_FIX_DUPLICATED_FLAGS)
+ @SystemApi
+ public static final long MATCH_CLONE_PROFILE_LONG = 1L << 34;
+
+ //-------------------------------------------------------------------------
+ // End of GET_ and MATCH_ flags
+ //-------------------------------------------------------------------------
+
+ /**
* Flag for {@link #addCrossProfileIntentFilter}: if this flag is set: when
* resolving an intent that matches the {@code CrossProfileIntentFilter},
* the current profile will be skipped. Only activities in the target user
diff --git a/core/java/android/content/pm/flags.aconfig b/core/java/android/content/pm/flags.aconfig
index 1b90570..b04b7ba 100644
--- a/core/java/android/content/pm/flags.aconfig
+++ b/core/java/android/content/pm/flags.aconfig
@@ -108,3 +108,10 @@
description: "Feature flag to reduce app crashes caused by split installs with INSTALL_DONT_KILL"
bug: "291212866"
}
+
+flag {
+ name: "fix_duplicated_flags"
+ namespace: "package_manager_service"
+ description: "Feature flag to fix duplicated PackageManager flag values"
+ bug: "314815969"
+}
diff --git a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
index d4d1ab3..8196bf5 100644
--- a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
@@ -1058,6 +1058,12 @@
* <p>The set returned is not modifiable, so any attempts to modify it will throw
* a {@code UnsupportedOperationException}.</p>
*
+ * <p>Devices launching on Android {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM}
+ * or newer versions are required to support {@link CaptureRequest#CONTROL_AF_MODE},
+ * {@link CaptureRequest#CONTROL_AF_REGIONS}, {@link CaptureRequest#CONTROL_AF_TRIGGER},
+ * {@link CaptureRequest#CONTROL_ZOOM_RATIO} for
+ * {@link CameraExtensionCharacteristics#EXTENSION_NIGHT}.</p>
+ *
* @param extension the extension type
*
* @return non-modifiable set of capture keys supported by camera extension session initialized
@@ -1139,6 +1145,12 @@
* and the {@link CameraExtensionSession.ExtensionCaptureCallback#onCaptureResultAvailable}
* callback will not be fired.</p>
*
+ * <p>Devices launching on Android {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM}
+ * or newer versions are required to support {@link CaptureResult#CONTROL_AF_MODE},
+ * {@link CaptureResult#CONTROL_AF_REGIONS}, {@link CaptureResult#CONTROL_AF_TRIGGER},
+ * {@link CaptureResult#CONTROL_AF_STATE}, {@link CaptureResult#CONTROL_ZOOM_RATIO} for
+ * {@link CameraExtensionCharacteristics#EXTENSION_NIGHT}.</p>
+ *
* @param extension the extension type
*
* @return non-modifiable set of capture result keys supported by camera extension session
diff --git a/core/java/android/os/IVibratorManagerService.aidl b/core/java/android/os/IVibratorManagerService.aidl
index 0f27569..65e498e 100644
--- a/core/java/android/os/IVibratorManagerService.aidl
+++ b/core/java/android/os/IVibratorManagerService.aidl
@@ -41,5 +41,5 @@
// There is no order guarantee with respect to the two-way APIs above like
// vibrate/isVibrating/cancel.
oneway void performHapticFeedback(int uid, int deviceId, String opPkg, int constant,
- boolean always, String reason, IBinder token);
+ boolean always, String reason);
}
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 7e07e1f..fc8523e 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -1599,7 +1599,7 @@
* fully removed, otherwise system resources may leak.
* @hide
*/
- public static final native int sendSignalToProcessGroup(int uid, int pid, int signal);
+ public static final native boolean sendSignalToProcessGroup(int uid, int pid, int signal);
/**
* Freeze the cgroup for the given UID.
diff --git a/core/java/android/os/SystemVibratorManager.java b/core/java/android/os/SystemVibratorManager.java
index bc85412e..8e83923 100644
--- a/core/java/android/os/SystemVibratorManager.java
+++ b/core/java/android/os/SystemVibratorManager.java
@@ -39,6 +39,7 @@
private final IVibratorManagerService mService;
private final Context mContext;
+ private final int mUid;
private final Binder mToken = new Binder();
private final Object mLock = new Object();
@GuardedBy("mLock")
@@ -56,6 +57,7 @@
public SystemVibratorManager(Context context) {
super(context);
mContext = context;
+ mUid = Process.myUid();
mService = IVibratorManagerService.Stub.asInterface(
ServiceManager.getService(Context.VIBRATOR_MANAGER_SERVICE));
}
@@ -152,8 +154,7 @@
}
try {
mService.performHapticFeedback(
- Process.myUid(), mContext.getDeviceId(), mPackageName, constant, always, reason,
- mToken);
+ mUid, mContext.getDeviceId(), mPackageName, constant, always, reason);
} catch (RemoteException e) {
Log.w(TAG, "Failed to perform haptic feedback.", e);
}
diff --git a/core/java/android/os/vibrator/flags.aconfig b/core/java/android/os/vibrator/flags.aconfig
index 437668c..69d86a6 100644
--- a/core/java/android/os/vibrator/flags.aconfig
+++ b/core/java/android/os/vibrator/flags.aconfig
@@ -44,10 +44,3 @@
description: "Enables the independent keyboard vibration settings feature"
bug: "289107579"
}
-
-flag {
- namespace: "haptics"
- name: "adaptive_haptics_enabled"
- description: "Enables the adaptive haptics feature"
- bug: "305961689"
-}
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 91dfc60..43e0c34 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -1238,7 +1238,7 @@
return killProcessGroup(uid, pid, SIGKILL);
}
-jint android_os_Process_sendSignalToProcessGroup(JNIEnv* env, jobject clazz, jint uid, jint pid,
+jboolean android_os_Process_sendSignalToProcessGroup(JNIEnv* env, jobject clazz, jint uid, jint pid,
jint signal) {
return sendSignalToProcessGroup(uid, pid, signal);
}
@@ -1310,7 +1310,7 @@
//{"setApplicationObject", "(Landroid/os/IBinder;)V",
//(void*)android_os_Process_setApplicationObject},
{"killProcessGroup", "(II)I", (void*)android_os_Process_killProcessGroup},
- {"sendSignalToProcessGroup", "(III)I", (void*)android_os_Process_sendSignalToProcessGroup},
+ {"sendSignalToProcessGroup", "(III)Z", (void*)android_os_Process_sendSignalToProcessGroup},
{"removeAllProcessGroups", "()V", (void*)android_os_Process_removeAllProcessGroups},
{"nativePidFdOpen", "(II)I", (void*)android_os_Process_nativePidFdOpen},
{"freezeCgroupUid", "(IZ)V", (void*)android_os_Process_freezeCgroupUID},
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index 0ad349b..88abaa1 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -179,8 +179,10 @@
"androidx.test.ext.junit",
"mockito_ravenwood",
"platform-test-annotations",
+ "flag-junit",
],
srcs: [
+ "src/android/os/BuildTest.java",
"src/android/os/FileUtilsTest.java",
"src/android/util/**/*.java",
"src/com/android/internal/util/**/*.java",
diff --git a/core/tests/coretests/src/android/os/BuildTest.java b/core/tests/coretests/src/android/os/BuildTest.java
index 2295eb9..3162e6d 100644
--- a/core/tests/coretests/src/android/os/BuildTest.java
+++ b/core/tests/coretests/src/android/os/BuildTest.java
@@ -16,19 +16,37 @@
package android.os;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.flag.junit.SetFlagsRule;
+import android.platform.test.ravenwood.RavenwoodRule;
+
import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import junit.framework.Assert;
-import junit.framework.TestCase;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
/**
* Provides test cases for android.os.Build and, in turn, many of the
* system properties set by the build system.
*/
-public class BuildTest extends TestCase {
-
+@RunWith(AndroidJUnit4.class)
+public class BuildTest {
private static final String TAG = "BuildTest";
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
/**
* Asserts that a String is non-null and non-empty. If it is not,
* an AssertionFailedError is thrown with the given message.
@@ -50,7 +68,9 @@
/**
* Asserts that all android.os.Build fields are non-empty and/or in a valid range.
*/
+ @Test
@SmallTest
+ @IgnoreUnderRavenwood(blockedBy = Build.class)
public void testBuildFields() throws Exception {
assertNotEmpty("ID", Build.ID);
assertNotEmpty("DISPLAY", Build.DISPLAY);
@@ -72,4 +92,16 @@
// (e.g., must be a C identifier, must be a valid filename, must not contain any spaces)
// add tests for them.
}
+
+ @Test
+ public void testFlagEnabled() throws Exception {
+ mSetFlagsRule.enableFlags(Flags.FLAG_ANDROID_OS_BUILD_VANILLA_ICE_CREAM);
+ assertTrue(Flags.androidOsBuildVanillaIceCream());
+ }
+
+ @Test
+ public void testFlagDisabled() throws Exception {
+ mSetFlagsRule.disableFlags(Flags.FLAG_ANDROID_OS_BUILD_VANILLA_ICE_CREAM);
+ assertFalse(Flags.androidOsBuildVanillaIceCream());
+ }
}
diff --git a/keystore/java/android/security/Authorization.java b/keystore/java/android/security/Authorization.java
index b4b3e92..4ec5e1b 100644
--- a/keystore/java/android/security/Authorization.java
+++ b/keystore/java/android/security/Authorization.java
@@ -26,7 +26,6 @@
import android.os.ServiceSpecificException;
import android.os.StrictMode;
import android.security.authorization.IKeystoreAuthorization;
-import android.security.authorization.LockScreenEvent;
import android.system.keystore2.ResponseCode;
import android.util.Log;
@@ -76,26 +75,37 @@
}
/**
- * Informs keystore2 about lock screen event.
+ * Tells Keystore that the device is now unlocked for a user.
*
- * @param locked - whether it is a lock (true) or unlock (false) event
- * @param syntheticPassword - if it is an unlock event with the password, pass the synthetic
- * password provided by the LockSettingService
- * @param unlockingSids - KeyMint secure user IDs that should be permitted to unlock
- * UNLOCKED_DEVICE_REQUIRED keys.
- *
+ * @param userId - the user's Android user ID
+ * @param password - a secret derived from the user's synthetic password, if the unlock method
+ * is LSKF (or equivalent) and thus has made the synthetic password available
* @return 0 if successful or a {@code ResponseCode}.
*/
- public static int onLockScreenEvent(@NonNull boolean locked, @NonNull int userId,
- @Nullable byte[] syntheticPassword, @Nullable long[] unlockingSids) {
+ public static int onDeviceUnlocked(int userId, @Nullable byte[] password) {
StrictMode.noteDiskWrite();
try {
- if (locked) {
- getService().onLockScreenEvent(LockScreenEvent.LOCK, userId, null, unlockingSids);
- } else {
- getService().onLockScreenEvent(
- LockScreenEvent.UNLOCK, userId, syntheticPassword, unlockingSids);
- }
+ getService().onDeviceUnlocked(userId, password);
+ return 0;
+ } catch (RemoteException | NullPointerException e) {
+ Log.w(TAG, "Can not connect to keystore", e);
+ return SYSTEM_ERROR;
+ } catch (ServiceSpecificException e) {
+ return e.errorCode;
+ }
+ }
+
+ /**
+ * Tells Keystore that the device is now locked for a user.
+ *
+ * @param userId - the user's Android user ID
+ * @param unlockingSids - list of biometric SIDs with which the device may be unlocked again
+ * @return 0 if successful or a {@code ResponseCode}.
+ */
+ public static int onDeviceLocked(int userId, @NonNull long[] unlockingSids) {
+ StrictMode.noteDiskWrite();
+ try {
+ getService().onDeviceLocked(userId, unlockingSids);
return 0;
} catch (RemoteException | NullPointerException e) {
Log.w(TAG, "Can not connect to keystore", e);
diff --git a/libs/hwui/jni/YuvToJpegEncoder.cpp b/libs/hwui/jni/YuvToJpegEncoder.cpp
index 0275e4f..3533001 100644
--- a/libs/hwui/jni/YuvToJpegEncoder.cpp
+++ b/libs/hwui/jni/YuvToJpegEncoder.cpp
@@ -401,7 +401,7 @@
if (int success = jpegREncoder.encodeJPEGR(&p010, &yuv420,
hdrTransferFunction,
&jpegR, jpegQuality,
- exif.length > 0 ? &exif : NULL); success != android::OK) {
+ exif.length > 0 ? &exif : NULL); success != JPEGR_NO_ERROR) {
ALOGW("Encode JPEG/R failed, error code: %d.", success);
return false;
}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/chart/BarChart.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/chart/BarChart.kt
index e761a33..caceb6f 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/chart/BarChart.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/chart/BarChart.kt
@@ -38,6 +38,8 @@
import com.android.settingslib.spa.framework.theme.divider
import com.github.mikephil.charting.charts.BarChart
import com.github.mikephil.charting.components.XAxis
+import com.github.mikephil.charting.components.YAxis
+import com.github.mikephil.charting.components.YAxis.AxisDependency
import com.github.mikephil.charting.data.BarData
import com.github.mikephil.charting.data.BarDataSet
import com.github.mikephil.charting.data.BarEntry
@@ -90,6 +92,10 @@
/** If set to true, touch gestures are enabled on the [BarChart]. */
val enableBarchartTouch: Boolean
get() = true
+
+ /** The renderer provider for x-axis. */
+ val xAxisRendererProvider: XAxisRendererProvider?
+ get() = null
}
data class BarChartData(
@@ -143,6 +149,16 @@
yOffset = 10f
}
+ barChartModel.xAxisRendererProvider?.let {
+ setXAxisRenderer(
+ it.provideXAxisRenderer(
+ getViewPortHandler(),
+ getXAxis(),
+ getTransformer(YAxis.AxisDependency.LEFT)
+ )
+ )
+ }
+
axisLeft.apply {
axisMaximum = barChartModel.yAxisMaxValue
axisMinimum = barChartModel.yAxisMinValue
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/chart/XAxisRendererProvider.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/chart/XAxisRendererProvider.kt
new file mode 100644
index 0000000..6569d25
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/chart/XAxisRendererProvider.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spa.widget.chart
+
+import com.github.mikephil.charting.components.XAxis
+import com.github.mikephil.charting.renderer.XAxisRenderer
+import com.github.mikephil.charting.utils.Transformer
+import com.github.mikephil.charting.utils.ViewPortHandler
+
+/** A provider for [XAxisRenderer] objects. */
+fun interface XAxisRendererProvider {
+
+ /** Provides an object of [XAxisRenderer] type. */
+ fun provideXAxisRenderer(
+ viewPortHandler: ViewPortHandler,
+ xAxis: XAxis,
+ transformer: Transformer
+ ): XAxisRenderer
+}
\ No newline at end of file
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index c2c5e00..7061e2c 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -281,6 +281,7 @@
"com_android_systemui_flags_lib",
"com_android_systemui_shared_flags_lib",
"flag-junit-base",
+ "platform-parametric-runner-lib",
"androidx.viewpager2_viewpager2",
"androidx.legacy_legacy-support-v4",
"androidx.recyclerview_recyclerview",
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 2970aaa..a26b311 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -211,6 +211,13 @@
}
flag {
+ name: "enable_layout_tracing"
+ namespace: "systemui"
+ description: "Enables detailed traversal slices during measure and layout in perfetto traces"
+ bug: "315274804"
+}
+
+flag {
name: "quick_settings_visual_haptics_longpress"
namespace: "systemui"
description: "Enable special visual and haptic effects for quick settings tiles with long-press actions"
diff --git a/packages/SystemUI/docs/executors.md b/packages/SystemUI/docs/executors.md
index 8520ce2..2d9438c 100644
--- a/packages/SystemUI/docs/executors.md
+++ b/packages/SystemUI/docs/executors.md
@@ -14,10 +14,10 @@
[FakeExecutor][FakeExecutor] is available.
[Executor]: https://developer.android.com/reference/java/util/concurrent/Executor.html
-[Handler]: https://developer.android.com/reference/android/os/Handler
+[Handler]: https://developer.android.com/reference/android/os/Handler.html
[Runnable]: https://developer.android.com/reference/java/lang/Runnable.html
[DelayableExecutor]: /packages/SystemUI/src/com/android/systemui/util/concurrency/DelayableExecutor.java
-[FakeExecutor]: /packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutor.java
+[FakeExecutor]: /packages/SystemUI/tests/utils/src/com/android/systemui/util/concurrency/FakeExecutor.java
## Rationale
@@ -117,7 +117,7 @@
postDelayed() | `none` | executeDelayed()
postAtTime() | `none` | executeAtTime()
-There is one notable gap in this implementation: `Handler.postAtFrontOfQueue()`.
+There are some notable gaps in this implementation: `Handler.postAtFrontOfQueue()`.
If you require this method, or similar, please reach out. The idea of a
PriorityQueueExecutor has been floated, but will not be implemented until there
is a clear need.
@@ -173,13 +173,20 @@
If you feel that you have a use case that this does not cover, please reach out.
+### ContentObserver
+
+One notable place where Handlers have been a requirement in the past is with
+[ContentObserver], which takes a Handler as an argument. However, we have created
+[ExecutorContentObserver], which is a hidden API that accepts an [Executor] in its
+constructor instead of a [Handler], and is otherwise identical.
+
+[ContentObserver]: https://developer.android.com/reference/android/database/ContentObserver.html
+[ExecutorContentObserver]: /core/java/android/database/ExecutorContentObserver.java
+
### Handlers Are Still Necessary
-Handlers aren't going away. There are Android APIs that still require them (even
-if future API development discourages them). A simple example is
-[ContentObserver][ContentObserver]. Use them where necessary.
-
-[ContentObserver]: https://developer.android.com/reference/android/database/ContentObserver
+Handlers aren't going away. There are other Android APIs that still require them.
+Avoid Handlers when possible, but use them where necessary.
## Testing (FakeExecutor)
@@ -314,6 +321,15 @@
The Runnables _will not_ interleave. All of one Executor's callbacks will run,
then all of the other's.
+### Testing Handlers without Loopers
+
+If a [Handler] is required because it is used by Android APIs, but is only
+used in simple ways (i.e. just `Handler.post(Runnable)`), you may still
+want the benefits of [FakeExecutor] when writing your tests, which
+you can get by wrapping the [Executor] in a mock for testing. This can be
+done with `com.android.systemui.util.concurrency.mockExecutorHandler` in
+`MockExecutorHandler.kt`.
+
### TestableLooper.RunWithLooper
As long as you're using FakeExecutors in all the code under test (and no
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt
index 661c345..2a02164 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt
@@ -313,6 +313,59 @@
}
@Test
+ fun isAutoConfirmEnabled_featureDisabled_returnsFalse() =
+ testScope.runTest {
+ val isAutoConfirmEnabled by collectLastValue(underTest.isAutoConfirmEnabled)
+ utils.authenticationRepository.setAutoConfirmFeatureEnabled(false)
+
+ assertThat(isAutoConfirmEnabled).isFalse()
+ }
+
+ @Test
+ fun isAutoConfirmEnabled_featureEnabled_returnsTrue() =
+ testScope.runTest {
+ val isAutoConfirmEnabled by collectLastValue(underTest.isAutoConfirmEnabled)
+ utils.authenticationRepository.setAutoConfirmFeatureEnabled(true)
+
+ assertThat(isAutoConfirmEnabled).isTrue()
+ }
+
+ @Test
+ fun isAutoConfirmEnabled_featureEnabledButDisabledByThrottling() =
+ testScope.runTest {
+ val isAutoConfirmEnabled by collectLastValue(underTest.isAutoConfirmEnabled)
+ val throttling by collectLastValue(underTest.throttling)
+ utils.authenticationRepository.setAutoConfirmFeatureEnabled(true)
+
+ // The feature is enabled.
+ assertThat(isAutoConfirmEnabled).isTrue()
+
+ // Make many wrong attempts to trigger throttling.
+ repeat(FakeAuthenticationRepository.MAX_FAILED_AUTH_TRIES_BEFORE_THROTTLING) {
+ underTest.authenticate(listOf(5, 6, 7)) // Wrong PIN
+ }
+ assertThat(throttling).isNotNull()
+
+ // Throttling disabled auto-confirm.
+ assertThat(isAutoConfirmEnabled).isFalse()
+
+ // Move the clock forward one more second, to completely finish the throttling period:
+ advanceTimeBy(FakeAuthenticationRepository.THROTTLE_DURATION_MS + 1000L)
+ assertThat(throttling).isNull()
+
+ // Auto-confirm is still disabled, because throttling occurred at least once in this
+ // session.
+ assertThat(isAutoConfirmEnabled).isFalse()
+
+ // Correct PIN and unlocks successfully, resetting the 'session'.
+ assertThat(underTest.authenticate(FakeAuthenticationRepository.DEFAULT_PIN))
+ .isEqualTo(AuthenticationResult.SUCCEEDED)
+
+ // Auto-confirm is re-enabled.
+ assertThat(isAutoConfirmEnabled).isTrue()
+ }
+
+ @Test
fun throttling() =
testScope.runTest {
val throttling by collectLastValue(underTest.throttling)
@@ -350,6 +403,7 @@
)
// Move the clock forward to ALMOST skip the throttling, leaving one second to go:
+ val throttleTimeoutSec = FakeAuthenticationRepository.THROTTLE_DURATION_SECONDS
repeat(FakeAuthenticationRepository.THROTTLE_DURATION_SECONDS - 1) { time ->
advanceTimeBy(1000)
assertThat(throttling)
@@ -358,8 +412,7 @@
failedAttemptCount =
FakeAuthenticationRepository
.MAX_FAILED_AUTH_TRIES_BEFORE_THROTTLING,
- remainingSeconds =
- FakeAuthenticationRepository.THROTTLE_DURATION_SECONDS - (time + 1),
+ remainingSeconds = throttleTimeoutSec - (time + 1),
)
)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
index 3cb97e3..61d55f0 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
@@ -19,6 +19,7 @@
package com.android.systemui.scene.domain.startable
import android.os.PowerManager
+import android.platform.test.annotations.EnableFlags
import android.view.Display
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -45,7 +46,6 @@
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
-import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.clearInvocations
@@ -55,6 +55,7 @@
@SmallTest
@RunWith(AndroidJUnit4::class)
+@EnableFlags(AconfigFlags.FLAG_SCENE_CONTAINER)
class SceneContainerStartableTest : SysuiTestCase() {
private val utils = SceneTestUtils(this)
@@ -93,11 +94,6 @@
authenticationInteractor = authenticationInteractor,
)
- @Before
- fun setUp() {
- mSetFlagsRule.enableFlags(AconfigFlags.FLAG_SCENE_CONTAINER)
- }
-
@Test
fun hydrateVisibility() =
testScope.runTest {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt b/packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt
index f1a4007..e27a328 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt
@@ -119,9 +119,8 @@
data class ReleasedFlag constructor(
override val name: String,
override val namespace: String,
- override val teamfood: Boolean = false,
override val overridden: Boolean = false
-) : BooleanFlag(name, namespace, true, teamfood, overridden)
+) : BooleanFlag(name, namespace, true, teamfood = false, overridden)
/**
* A Flag that reads its default values from a resource overlay instead of code.
@@ -132,8 +131,9 @@
override val name: String,
override val namespace: String,
@BoolRes override val resourceId: Int,
+) : ResourceFlag<Boolean> {
override val teamfood: Boolean = false
-) : ResourceFlag<Boolean>
+}
/**
* A Flag that can reads its overrides from System Properties.
@@ -147,7 +147,6 @@
override val namespace: String,
override val default: Boolean = false,
) : SysPropFlag<Boolean> {
- // TODO(b/268520433): Teamfood not supported for sysprop flags yet.
override val teamfood: Boolean = false
}
diff --git a/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsFactory.kt b/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsFactory.kt
index aef8371..f9fe67a 100644
--- a/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsFactory.kt
+++ b/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsFactory.kt
@@ -42,7 +42,7 @@
name: String,
namespace: String = "systemui",
): ReleasedFlag {
- val flag = ReleasedFlag(name = name, namespace = namespace, teamfood = false)
+ val flag = ReleasedFlag(name = name, namespace = namespace)
checkForDupesAndAdd(flag)
return flag
}
@@ -57,7 +57,6 @@
name = name,
namespace = namespace,
resourceId = resourceId,
- teamfood = false,
)
checkForDupesAndAdd(flag)
return flag
diff --git a/packages/SystemUI/src-release/com/android/systemui/flags/FlagsFactory.kt b/packages/SystemUI/src-release/com/android/systemui/flags/FlagsFactory.kt
index f4b4296..aedf0ce 100644
--- a/packages/SystemUI/src-release/com/android/systemui/flags/FlagsFactory.kt
+++ b/packages/SystemUI/src-release/com/android/systemui/flags/FlagsFactory.kt
@@ -42,7 +42,7 @@
name: String,
namespace: String = "systemui",
): ReleasedFlag {
- val flag = ReleasedFlag(name = name, namespace = namespace, teamfood = false)
+ val flag = ReleasedFlag(name = name, namespace = namespace)
flagMap[name] = flag
return flag
}
@@ -57,7 +57,6 @@
name = name,
namespace = namespace,
resourceId = resourceId,
- teamfood = false,
)
flagMap[name] = flag
return flag
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index bf44517..c3f6480 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -110,6 +110,10 @@
View.setTracedRequestLayoutClassClass(
SystemProperties.get("persist.debug.trace_request_layout_class", null));
+ if (Flags.enableLayoutTracing()) {
+ View.setTraceLayoutSteps(true);
+ }
+
if (Process.myUserHandle().equals(UserHandle.SYSTEM)) {
IntentFilter bootCompletedFilter = new
IntentFilter(Intent.ACTION_LOCKED_BOOT_COMPLETED);
diff --git a/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt b/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt
index dd4ca92..bd84b28 100644
--- a/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt
@@ -60,14 +60,6 @@
/** Defines interface for classes that can access authentication-related application state. */
interface AuthenticationRepository {
/**
- * Whether the auto confirm feature is enabled for the currently-selected user.
- *
- * Note that the length of the PIN is also important to take into consideration, please see
- * [hintedPinLength].
- */
- val isAutoConfirmFeatureEnabled: StateFlow<Boolean>
-
- /**
* Emits the result whenever a PIN/Pattern/Password security challenge is attempted by the user
* in order to unlock the device.
*/
@@ -93,6 +85,17 @@
*/
val throttling: MutableStateFlow<AuthenticationThrottlingModel?>
+ /** Whether throttling has occurred at least once since the last successful authentication. */
+ val hasThrottlingOccurred: MutableStateFlow<Boolean>
+
+ /**
+ * Whether the auto confirm feature is enabled for the currently-selected user.
+ *
+ * Note that the length of the PIN is also important to take into consideration, please see
+ * [hintedPinLength].
+ */
+ val isAutoConfirmFeatureEnabled: StateFlow<Boolean>
+
/**
* The currently-configured authentication method. This determines how the authentication
* challenge needs to be completed in order to unlock an otherwise locked device.
@@ -172,11 +175,6 @@
mobileConnectionsRepository: MobileConnectionsRepository,
) : AuthenticationRepository {
- override val isAutoConfirmFeatureEnabled: StateFlow<Boolean> =
- refreshingFlow(
- initialValue = false,
- getFreshValue = lockPatternUtils::isAutoPinConfirmEnabled,
- )
override val authenticationChallengeResult = MutableSharedFlow<Boolean>()
override val hintedPinLength: Int = 6
@@ -190,8 +188,13 @@
override val throttling: MutableStateFlow<AuthenticationThrottlingModel?> =
MutableStateFlow(null)
- private val selectedUserId: Int
- get() = userRepository.getSelectedUserInfo().id
+ override val hasThrottlingOccurred: MutableStateFlow<Boolean> = MutableStateFlow(false)
+
+ override val isAutoConfirmFeatureEnabled: StateFlow<Boolean> =
+ refreshingFlow(
+ initialValue = false,
+ getFreshValue = lockPatternUtils::isAutoPinConfirmEnabled,
+ )
override val authenticationMethod: Flow<AuthenticationMethodModel> =
combine(userRepository.selectedUserInfo, mobileConnectionsRepository.isAnySimSecure) {
@@ -280,6 +283,9 @@
}
}
+ private val selectedUserId: Int
+ get() = userRepository.getSelectedUserInfo().id
+
/**
* Returns a [StateFlow] that's automatically kept fresh. The passed-in [getFreshValue] is
* invoked on a background thread every time the selected user is changed and every time a new
diff --git a/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt b/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
index 4e67771..7f8f887 100644
--- a/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
@@ -95,15 +95,14 @@
*
* Note that the length of the PIN is also important to take into consideration, please see
* [hintedPinLength].
- *
- * During throttling, this is always disabled (`false`).
*/
val isAutoConfirmEnabled: StateFlow<Boolean> =
- combine(repository.isAutoConfirmFeatureEnabled, repository.throttling) {
+ combine(repository.isAutoConfirmFeatureEnabled, repository.hasThrottlingOccurred) {
featureEnabled,
- throttling ->
- // Disable auto-confirm during throttling.
- featureEnabled && throttling == null
+ hasThrottlingOccurred ->
+ // Disable auto-confirm if throttling occurred since the last successful
+ // authentication attempt.
+ featureEnabled && !hasThrottlingOccurred
}
.stateIn(
scope = applicationScope,
@@ -221,6 +220,7 @@
repository.setThrottleDuration(
durationMs = authenticationResult.throttleDurationMs,
)
+ repository.hasThrottlingOccurred.value = true
startThrottlingCountdown()
}
@@ -228,6 +228,8 @@
// Since authentication succeeded, we should refresh throttling to make sure that our
// state is completely reflecting the upstream source of truth.
refreshThrottling()
+
+ repository.hasThrottlingOccurred.value = false
}
return if (authenticationResult.isSuccessful) {
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsClassicDebug.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsClassicDebug.java
index 87c12b4..72b0891 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsClassicDebug.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsClassicDebug.java
@@ -25,7 +25,6 @@
import static com.android.systemui.flags.FlagManager.EXTRA_VALUE;
import static com.android.systemui.flags.FlagsCommonModule.ALL_FLAGS;
import static com.android.systemui.shared.Flags.exampleSharedFlag;
-
import static java.util.Objects.requireNonNull;
import android.content.BroadcastReceiver;
@@ -508,9 +507,7 @@
enabled = isEnabled((ResourceBooleanFlag) f);
overridden = readBooleanFlagOverride(f.getName()) != null;
} else if (f instanceof SysPropBooleanFlag) {
- // TODO(b/223379190): Teamfood not supported for sysprop flags yet.
enabled = isEnabled((SysPropBooleanFlag) f);
- teamfood = false;
overridden = !mSystemProperties.get(f.getName()).isEmpty();
} else {
// TODO: add support for other flag types.
@@ -519,7 +516,7 @@
}
if (enabled) {
- return new ReleasedFlag(f.getName(), f.getNamespace(), teamfood, overridden);
+ return new ReleasedFlag(f.getName(), f.getNamespace(), overridden);
} else {
return new UnreleasedFlag(f.getName(), f.getNamespace(), teamfood, overridden);
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt b/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
index 6a0e882..d5b95d67 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
@@ -16,7 +16,10 @@
package com.android.systemui.flags
+import com.android.systemui.Flags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR
+import com.android.systemui.Flags.keyguardBottomAreaRefactor
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.shared.KeyguardShadeMigrationNssl
import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor
import com.android.systemui.statusbar.notification.shared.NotificationIconContainerRefactor
import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor
@@ -29,5 +32,9 @@
override fun defineDependencies() {
NotificationsLiveDataStoreRefactor.token dependsOn NotificationIconContainerRefactor.token
FooterViewRefactor.token dependsOn NotificationIconContainerRefactor.token
+
+ val keyguardBottomAreaRefactor = FlagToken(
+ FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR, keyguardBottomAreaRefactor())
+ KeyguardShadeMigrationNssl.token dependsOn keyguardBottomAreaRefactor
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
index cbfd17ff..9fe5c3f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
@@ -214,7 +214,7 @@
private fun listenForLockscreenToPrimaryBouncerDragging() {
var transitionId: UUID? = null
scope.launch("$TAG#listenForLockscreenToPrimaryBouncerDragging") {
- shadeRepository.shadeModel
+ shadeRepository.legacyShadeExpansion
.sample(
combine(
transitionInteractor.startedKeyguardTransitionStep,
@@ -224,23 +224,23 @@
),
::toQuad
)
- .collect { (shadeModel, keyguardState, statusBarState, isKeyguardUnlocked) ->
+ .collect { (shadeExpansion, keyguardState, statusBarState, isKeyguardUnlocked) ->
val id = transitionId
if (id != null) {
if (keyguardState.to == KeyguardState.PRIMARY_BOUNCER) {
// An existing `id` means a transition is started, and calls to
// `updateTransition` will control it until FINISHED or CANCELED
var nextState =
- if (shadeModel.expansionAmount == 0f) {
+ if (shadeExpansion == 0f) {
TransitionState.FINISHED
- } else if (shadeModel.expansionAmount == 1f) {
+ } else if (shadeExpansion == 1f) {
TransitionState.CANCELED
} else {
TransitionState.RUNNING
}
transitionRepository.updateTransition(
id,
- 1f - shadeModel.expansionAmount,
+ 1f - shadeExpansion,
nextState,
)
@@ -274,7 +274,7 @@
// integrated into KeyguardTransitionRepository
if (
keyguardState.to == KeyguardState.LOCKSCREEN &&
- shadeModel.isUserDragging &&
+ shadeRepository.legacyShadeTracking.value &&
!isKeyguardUnlocked &&
statusBarState == KEYGUARD
) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index 702386d..c12efe8 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -224,8 +224,8 @@
configurationInteractor
.dimensionPixelSize(R.dimen.keyguard_translate_distance_on_swipe_up)
.flatMapLatest { translationDistance ->
- shadeRepository.shadeModel.map {
- if (it.expansionAmount == 0f) {
+ shadeRepository.legacyShadeExpansion.map {
+ if (it == 0f) {
// Reset the translation value
0f
} else {
@@ -233,7 +233,7 @@
MathUtils.lerp(
translationDistance,
0,
- Interpolators.FAST_OUT_LINEAR_IN.getInterpolation(it.expansionAmount)
+ Interpolators.FAST_OUT_LINEAR_IN.getInterpolation(it)
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt b/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt
index e94a3eb..2445bdb 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt
@@ -15,25 +15,14 @@
*/
package com.android.systemui.shade.data.repository
-import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
-import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.shade.ShadeExpansionChangeEvent
-import com.android.systemui.shade.ShadeExpansionListener
-import com.android.systemui.shade.ShadeExpansionStateManager
-import com.android.systemui.shade.domain.model.ShadeModel
import javax.inject.Inject
-import kotlinx.coroutines.channels.awaitClose
-import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
-import kotlinx.coroutines.flow.distinctUntilChanged
+/** Data for the shade, mostly related to expansion of the shade and quick settings. */
interface ShadeRepository {
- /** ShadeModel information regarding shade expansion events */
- val shadeModel: Flow<ShadeModel>
-
/**
* Amount qs has expanded, [0-1]. 0 means fully collapsed, 1 means fully expanded. Quick
* Settings can be expanded without the full shade expansion.
@@ -167,34 +156,7 @@
/** Business logic for shade interactions */
@SysUISingleton
-class ShadeRepositoryImpl
-@Inject
-constructor(shadeExpansionStateManager: ShadeExpansionStateManager) : ShadeRepository {
- override val shadeModel: Flow<ShadeModel> =
- conflatedCallbackFlow {
- val callback =
- object : ShadeExpansionListener {
- override fun onPanelExpansionChanged(event: ShadeExpansionChangeEvent) {
- // Don't propagate ShadeExpansionChangeEvent.dragDownPxAmount field.
- // It is too noisy and produces extra events that consumers won't care
- // about
- val info =
- ShadeModel(
- expansionAmount = event.fraction,
- isExpanded = event.expanded,
- isUserDragging = event.tracking
- )
- trySendWithFailureLogging(info, TAG, "updated shade expansion info")
- }
- }
-
- val currentState = shadeExpansionStateManager.addExpansionListener(callback)
- callback.onPanelExpansionChanged(currentState)
-
- awaitClose { shadeExpansionStateManager.removeExpansionListener(callback) }
- }
- .distinctUntilChanged()
-
+class ShadeRepositoryImpl @Inject constructor() : ShadeRepository {
private val _qsExpansion = MutableStateFlow(0f)
override val qsExpansion: StateFlow<Float> = _qsExpansion.asStateFlow()
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/model/ShadeModel.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/model/ShadeModel.kt
deleted file mode 100644
index ce0f4283..0000000
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/model/ShadeModel.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-package com.android.systemui.shade.domain.model
-
-import android.annotation.FloatRange
-
-/** Information about shade (NotificationPanel) expansion */
-data class ShadeModel(
- /** 0 when collapsed, 1 when fully expanded. */
- @FloatRange(from = 0.0, to = 1.0) val expansionAmount: Float = 0f,
- /** Whether the panel should be considered expanded */
- val isExpanded: Boolean = false,
- /** Whether the user is actively dragging the panel. */
- val isUserDragging: Boolean = false,
-)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
index faffb3e..d23c85a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
@@ -19,7 +19,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Handler;
-import android.os.SystemClock;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.view.accessibility.AccessibilityEvent;
@@ -29,6 +28,7 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
import com.android.systemui.statusbar.policy.HeadsUpManagerLogger;
+import com.android.systemui.util.time.SystemClock;
import java.util.stream.Stream;
@@ -39,21 +39,23 @@
*/
public abstract class AlertingNotificationManager {
private static final String TAG = "AlertNotifManager";
- protected final Clock mClock = new Clock();
+ protected final SystemClock mSystemClock;
protected final ArrayMap<String, AlertEntry> mAlertEntries = new ArrayMap<>();
protected final HeadsUpManagerLogger mLogger;
- public AlertingNotificationManager(HeadsUpManagerLogger logger, @Main Handler handler) {
- mLogger = logger;
- mHandler = handler;
- }
-
protected int mMinimumDisplayTime;
- protected int mStickyDisplayTime;
- protected int mAutoDismissNotificationDecay;
+ protected int mStickyForSomeTimeAutoDismissTime;
+ protected int mAutoDismissTime;
@VisibleForTesting
public Handler mHandler;
+ public AlertingNotificationManager(HeadsUpManagerLogger logger, @Main Handler handler,
+ SystemClock systemClock) {
+ mLogger = logger;
+ mHandler = handler;
+ mSystemClock = systemClock;
+ }
+
/**
* Called when posting a new notification that should alert the user and appear on screen.
* Adds the notification to be managed.
@@ -251,7 +253,7 @@
public long getEarliestRemovalTime(String key) {
AlertEntry alerting = mAlertEntries.get(key);
if (alerting != null) {
- return Math.max(0, alerting.mEarliestRemovaltime - mClock.currentTimeMillis());
+ return Math.max(0, alerting.mEarliestRemovalTime - mSystemClock.elapsedRealtime());
}
return 0;
}
@@ -259,7 +261,7 @@
protected class AlertEntry implements Comparable<AlertEntry> {
@Nullable public NotificationEntry mEntry;
public long mPostTime;
- public long mEarliestRemovaltime;
+ public long mEarliestRemovalTime;
@Nullable protected Runnable mRemoveAlertRunnable;
@@ -283,8 +285,8 @@
public void updateEntry(boolean updatePostTime, @Nullable String reason) {
mLogger.logUpdateEntry(mEntry, updatePostTime, reason);
- final long now = mClock.currentTimeMillis();
- mEarliestRemovaltime = now + mMinimumDisplayTime;
+ final long now = mSystemClock.elapsedRealtime();
+ mEarliestRemovalTime = now + mMinimumDisplayTime;
if (updatePostTime) {
mPostTime = Math.max(mPostTime, now);
@@ -318,7 +320,7 @@
* @return true if the notification has been on screen long enough
*/
public boolean wasShownLongEnough() {
- return mEarliestRemovaltime < mClock.currentTimeMillis();
+ return mEarliestRemovalTime < mSystemClock.elapsedRealtime();
}
@Override
@@ -351,7 +353,7 @@
if (mRemoveAlertRunnable != null) {
removeAutoRemovalCallbacks("removeAsSoonAsPossible (will be rescheduled)");
- final long timeLeft = mEarliestRemovaltime - mClock.currentTimeMillis();
+ final long timeLeft = mEarliestRemovalTime - mSystemClock.elapsedRealtime();
mHandler.postDelayed(mRemoveAlertRunnable, timeLeft);
}
}
@@ -361,22 +363,16 @@
* @return the post time
*/
protected long calculatePostTime() {
- return mClock.currentTimeMillis();
+ return mSystemClock.elapsedRealtime();
}
/**
* @return When the notification should auto-dismiss itself, based on
- * {@link SystemClock#elapsedRealTime()}
+ * {@link SystemClock#elapsedRealtime()}
*/
protected long calculateFinishTime() {
// Overridden by HeadsUpManager HeadsUpEntry #calculateFinishTime
return 0;
}
}
-
- protected final static class Clock {
- public long currentTimeMillis() {
- return SystemClock.elapsedRealtime();
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index 3a95e6d..644c896 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -49,6 +49,8 @@
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
import com.android.systemui.statusbar.policy.OnHeadsUpPhoneListenerChange;
import com.android.systemui.util.kotlin.JavaAdapter;
+import com.android.systemui.util.settings.GlobalSettings;
+import com.android.systemui.util.time.SystemClock;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -115,11 +117,14 @@
VisualStabilityProvider visualStabilityProvider,
ConfigurationController configurationController,
@Main Handler handler,
+ GlobalSettings globalSettings,
+ SystemClock systemClock,
AccessibilityManagerWrapper accessibilityManagerWrapper,
UiEventLogger uiEventLogger,
JavaAdapter javaAdapter,
ShadeInteractor shadeInteractor) {
- super(context, logger, handler, accessibilityManagerWrapper, uiEventLogger);
+ super(context, logger, handler, globalSettings, systemClock, accessibilityManagerWrapper,
+ uiEventLogger);
Resources resources = mContext.getResources();
mExtensionTime = resources.getInteger(R.integer.ambient_notification_extension_time);
statusBarStateController.addCallback(mStatusBarStateListener);
@@ -206,7 +211,7 @@
@Override
public boolean shouldSwallowClick(@NonNull String key) {
BaseHeadsUpManager.HeadsUpEntry entry = getHeadsUpEntry(key);
- return entry != null && mClock.currentTimeMillis() < entry.mPostTime;
+ return entry != null && mSystemClock.elapsedRealtime() < entry.mPostTime;
}
public void onExpandingFinished() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java
index cec76f3..8054b04 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java
@@ -25,8 +25,6 @@
import android.content.res.Resources;
import android.database.ContentObserver;
import android.os.Handler;
-import android.os.SystemClock;
-import android.provider.Settings;
import android.util.ArrayMap;
import android.view.accessibility.AccessibilityManager;
@@ -40,6 +38,8 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
import com.android.systemui.util.ListenerSet;
+import com.android.systemui.util.settings.GlobalSettings;
+import com.android.systemui.util.time.SystemClock;
import java.io.PrintWriter;
@@ -85,36 +85,40 @@
public BaseHeadsUpManager(@NonNull final Context context,
HeadsUpManagerLogger logger,
@Main Handler handler,
+ GlobalSettings globalSettings,
+ SystemClock systemClock,
AccessibilityManagerWrapper accessibilityManagerWrapper,
UiEventLogger uiEventLogger) {
- super(logger, handler);
+ super(logger, handler, systemClock);
mContext = context;
mAccessibilityMgr = accessibilityManagerWrapper;
mUiEventLogger = uiEventLogger;
Resources resources = context.getResources();
mMinimumDisplayTime = resources.getInteger(R.integer.heads_up_notification_minimum_time);
- mStickyDisplayTime = resources.getInteger(R.integer.sticky_heads_up_notification_time);
- mAutoDismissNotificationDecay = resources.getInteger(R.integer.heads_up_notification_decay);
+ mStickyForSomeTimeAutoDismissTime = resources.getInteger(
+ R.integer.sticky_heads_up_notification_time);
+ mAutoDismissTime = resources.getInteger(R.integer.heads_up_notification_decay);
mTouchAcceptanceDelay = resources.getInteger(R.integer.touch_acceptance_delay);
mSnoozedPackages = new ArrayMap<>();
int defaultSnoozeLengthMs =
resources.getInteger(R.integer.heads_up_default_snooze_length_ms);
- mSnoozeLengthMs = Settings.Global.getInt(context.getContentResolver(),
- SETTING_HEADS_UP_SNOOZE_LENGTH_MS, defaultSnoozeLengthMs);
+ mSnoozeLengthMs = globalSettings.getInt(SETTING_HEADS_UP_SNOOZE_LENGTH_MS,
+ defaultSnoozeLengthMs);
ContentObserver settingsObserver = new ContentObserver(handler) {
@Override
public void onChange(boolean selfChange) {
- final int packageSnoozeLengthMs = Settings.Global.getInt(
- context.getContentResolver(), SETTING_HEADS_UP_SNOOZE_LENGTH_MS, -1);
+ final int packageSnoozeLengthMs = globalSettings.getInt(
+ SETTING_HEADS_UP_SNOOZE_LENGTH_MS, -1);
if (packageSnoozeLengthMs > -1 && packageSnoozeLengthMs != mSnoozeLengthMs) {
mSnoozeLengthMs = packageSnoozeLengthMs;
mLogger.logSnoozeLengthChange(packageSnoozeLengthMs);
}
}
};
- context.getContentResolver().registerContentObserver(
- Settings.Global.getUriFor(SETTING_HEADS_UP_SNOOZE_LENGTH_MS), false,
+ globalSettings.registerContentObserver(
+ globalSettings.getUriFor(SETTING_HEADS_UP_SNOOZE_LENGTH_MS),
+ /* notifyForDescendants = */ false,
settingsObserver);
}
@@ -231,7 +235,7 @@
final String key = snoozeKey(packageName, mUser);
Long snoozedUntil = mSnoozedPackages.get(key);
if (snoozedUntil != null) {
- if (snoozedUntil > mClock.currentTimeMillis()) {
+ if (snoozedUntil > mSystemClock.elapsedRealtime()) {
mLogger.logIsSnoozedReturned(key);
return true;
}
@@ -250,7 +254,7 @@
String packageName = entry.mEntry.getSbn().getPackageName();
String snoozeKey = snoozeKey(packageName, mUser);
mLogger.logPackageSnoozed(snoozeKey);
- mSnoozedPackages.put(snoozeKey, mClock.currentTimeMillis() + mSnoozeLengthMs);
+ mSnoozedPackages.put(snoozeKey, mSystemClock.elapsedRealtime() + mSnoozeLengthMs);
}
}
@@ -308,7 +312,7 @@
protected void dumpInternal(@NonNull PrintWriter pw, @NonNull String[] args) {
pw.print(" mTouchAcceptanceDelay="); pw.println(mTouchAcceptanceDelay);
pw.print(" mSnoozeLengthMs="); pw.println(mSnoozeLengthMs);
- pw.print(" now="); pw.println(mClock.currentTimeMillis());
+ pw.print(" now="); pw.println(mSystemClock.elapsedRealtime());
pw.print(" mUser="); pw.println(mUser);
for (AlertEntry entry: mAlertEntries.values()) {
pw.print(" HeadsUpEntry="); pw.println(entry.mEntry);
@@ -519,12 +523,12 @@
/**
* @return When the notification should auto-dismiss itself, based on
- * {@link SystemClock#elapsedRealTime()}
+ * {@link SystemClock#elapsedRealtime()}
*/
@Override
protected long calculateFinishTime() {
final long duration = getRecommendedHeadsUpTimeoutMs(
- isStickyForSomeTime() ? mStickyDisplayTime : mAutoDismissNotificationDecay);
+ isStickyForSomeTime() ? mStickyForSomeTimeAutoDismissTime : mAutoDismissTime);
return mPostTime + duration;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java
index 2a1cfd1..215f93d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java
@@ -17,7 +17,6 @@
package com.android.systemui.accessibility.floatingmenu;
import static com.google.common.truth.Truth.assertThat;
-
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -26,9 +25,7 @@
import static org.mockito.Mockito.verifyZeroInteractions;
import android.graphics.PointF;
-import android.platform.test.annotations.RequiresFlagsEnabled;
-import android.platform.test.flag.junit.CheckFlagsRule;
-import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+import android.platform.test.annotations.EnableFlags;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.View;
@@ -74,10 +71,6 @@
@Rule
public MockitoRule mockito = MockitoJUnit.rule();
- @Rule
- public final CheckFlagsRule mCheckFlagsRule =
- DeviceFlagsValueProvider.createCheckFlagsRule();
-
@Mock
private AccessibilityManager mAccessibilityManager;
@@ -233,7 +226,7 @@
}
@Test
- @RequiresFlagsEnabled(Flags.FLAG_FLOATING_MENU_ANIMATED_TUCK)
+ @EnableFlags(Flags.FLAG_FLOATING_MENU_ANIMATED_TUCK)
public void tuck_animates() {
mMenuAnimationController.cancelAnimations();
mMenuAnimationController.moveToEdgeAndHide();
@@ -242,7 +235,7 @@
}
@Test
- @RequiresFlagsEnabled(Flags.FLAG_FLOATING_MENU_ANIMATED_TUCK)
+ @EnableFlags(Flags.FLAG_FLOATING_MENU_ANIMATED_TUCK)
public void untuck_animates() {
mMenuAnimationController.cancelAnimations();
mMenuAnimationController.moveOutEdgeAndShow();
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 0f1364d..be6f3ff 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
@@ -21,11 +21,8 @@
import static android.view.WindowInsets.Type.displayCutout;
import static android.view.WindowInsets.Type.ime;
import static android.view.WindowInsets.Type.systemBars;
-
import static com.android.systemui.accessibility.floatingmenu.MenuViewLayer.LayerIndex;
-
import static com.google.common.truth.Truth.assertThat;
-
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -41,10 +38,8 @@
import android.graphics.Rect;
import android.os.Build;
import android.os.UserHandle;
-import android.platform.test.annotations.RequiresFlagsDisabled;
-import android.platform.test.annotations.RequiresFlagsEnabled;
-import android.platform.test.flag.junit.CheckFlagsRule;
-import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -103,10 +98,6 @@
@Rule
public MockitoRule mockito = MockitoJUnit.rule();
- @Rule
- public final CheckFlagsRule mCheckFlagsRule =
- DeviceFlagsValueProvider.createCheckFlagsRule();
-
@Mock
private IAccessibilityFloatingMenu mFloatingMenu;
@@ -230,7 +221,7 @@
}
@Test
- @RequiresFlagsDisabled(Flags.FLAG_FLOATING_MENU_IME_DISPLACEMENT_ANIMATION)
+ @DisableFlags(Flags.FLAG_FLOATING_MENU_IME_DISPLACEMENT_ANIMATION)
public void showingImeInsetsChange_overlapOnIme_menuShownAboveIme_old() {
mMenuAnimationController.moveAndPersistPosition(new PointF(0, IME_TOP + 100));
final PointF beforePosition = mMenuView.getMenuPosition();
@@ -243,7 +234,7 @@
}
@Test
- @RequiresFlagsEnabled(Flags.FLAG_FLOATING_MENU_IME_DISPLACEMENT_ANIMATION)
+ @EnableFlags(Flags.FLAG_FLOATING_MENU_IME_DISPLACEMENT_ANIMATION)
public void showingImeInsetsChange_overlapOnIme_menuShownAboveIme() {
mMenuAnimationController.moveAndPersistPosition(new PointF(0, IME_TOP + 100));
final PointF beforePosition = mMenuView.getMenuPosition();
@@ -259,7 +250,7 @@
}
@Test
- @RequiresFlagsDisabled(Flags.FLAG_FLOATING_MENU_IME_DISPLACEMENT_ANIMATION)
+ @DisableFlags(Flags.FLAG_FLOATING_MENU_IME_DISPLACEMENT_ANIMATION)
public void hidingImeInsetsChange_overlapOnIme_menuBackToOriginalPosition_old() {
mMenuAnimationController.moveAndPersistPosition(new PointF(0, IME_TOP + 200));
final PointF beforePosition = mMenuView.getMenuPosition();
@@ -271,7 +262,7 @@
}
@Test
- @RequiresFlagsEnabled(Flags.FLAG_FLOATING_MENU_IME_DISPLACEMENT_ANIMATION)
+ @EnableFlags(Flags.FLAG_FLOATING_MENU_IME_DISPLACEMENT_ANIMATION)
public void hidingImeInsetsChange_overlapOnIme_menuBackToOriginalPosition() {
mMenuAnimationController.moveAndPersistPosition(new PointF(0, IME_TOP + 200));
final PointF beforePosition = mMenuView.getMenuPosition();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java
index 8f0a97c..8da6cf9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java
@@ -17,9 +17,7 @@
package com.android.systemui.accessibility.floatingmenu;
import static android.app.UiModeManager.MODE_NIGHT_YES;
-
import static com.google.common.truth.Truth.assertThat;
-
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -27,9 +25,7 @@
import android.app.UiModeManager;
import android.graphics.Rect;
import android.graphics.drawable.GradientDrawable;
-import android.platform.test.annotations.RequiresFlagsEnabled;
-import android.platform.test.flag.junit.CheckFlagsRule;
-import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+import android.platform.test.annotations.EnableFlags;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.WindowManager;
@@ -66,10 +62,6 @@
@Rule
public MockitoRule mockito = MockitoJUnit.rule();
- @Rule
- public final CheckFlagsRule mCheckFlagsRule =
- DeviceFlagsValueProvider.createCheckFlagsRule();
-
@Mock
private AccessibilityManager mAccessibilityManager;
@@ -147,7 +139,7 @@
}
@Test
- @RequiresFlagsEnabled(Flags.FLAG_FLOATING_MENU_RADII_ANIMATION)
+ @EnableFlags(Flags.FLAG_FLOATING_MENU_RADII_ANIMATION)
public void onEdgeChanged_startsRadiiAnimation() {
final RadiiAnimator radiiAnimator = getRadiiAnimator();
mMenuView.onEdgeChanged();
@@ -155,7 +147,7 @@
}
@Test
- @RequiresFlagsEnabled(Flags.FLAG_FLOATING_MENU_RADII_ANIMATION)
+ @EnableFlags(Flags.FLAG_FLOATING_MENU_RADII_ANIMATION)
public void onDraggingStart_startsRadiiAnimation() {
final RadiiAnimator radiiAnimator = getRadiiAnimator();
mMenuView.onDraggingStart();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/DefaultUdfpsTouchOverlayViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/DefaultUdfpsTouchOverlayViewModelTest.kt
index 575d8bf..fa17672 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/DefaultUdfpsTouchOverlayViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/DefaultUdfpsTouchOverlayViewModelTest.kt
@@ -30,7 +30,6 @@
import com.android.systemui.runCurrent
import com.android.systemui.runTest
import com.android.systemui.shade.data.repository.FakeShadeRepository
-import com.android.systemui.shade.domain.model.ShadeModel
import com.android.systemui.statusbar.phone.SystemUIDialogManager
import com.android.systemui.user.domain.UserDomainLayerModule
import com.android.systemui.util.mockito.mock
@@ -83,23 +82,13 @@
private fun TestComponent.shadeExpanded(expanded: Boolean) {
if (expanded) {
- shadeRepository.setShadeModel(
- ShadeModel(
- expansionAmount = 1f,
- isExpanded = true,
- isUserDragging = false,
- )
- )
+ shadeRepository.setLegacyShadeExpansion(1f)
+ shadeRepository.setLegacyShadeTracking(false)
shadeRepository.setLegacyExpandedOrAwaitingInputTransfer(true)
} else {
keyguardRepository.setStatusBarState(StatusBarState.SHADE)
- shadeRepository.setShadeModel(
- ShadeModel(
- expansionAmount = 0f,
- isExpanded = false,
- isUserDragging = false,
- )
- )
+ shadeRepository.setLegacyShadeExpansion(0f)
+ shadeRepository.setLegacyShadeTracking(false)
shadeRepository.setLegacyExpandedOrAwaitingInputTransfer(false)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractorTest.kt
index 42b0f50..37c7409 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractorTest.kt
@@ -18,6 +18,7 @@
import android.companion.virtual.VirtualDeviceManager
import android.companion.virtual.flags.Flags.FLAG_INTERACTIVE_SCREEN_MIRROR
+import android.platform.test.annotations.EnableFlags
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.Display
@@ -75,7 +76,6 @@
@Before
fun setup() {
- mSetFlagsRule.disableFlags(FLAG_INTERACTIVE_SCREEN_MIRROR)
whenever(virtualDeviceManager.isVirtualDeviceOwnedMirrorDisplay(anyInt())).thenReturn(false)
fakeKeyguardRepository.setKeyguardShowing(false)
}
@@ -160,9 +160,9 @@
}
@Test
+ @EnableFlags(FLAG_INTERACTIVE_SCREEN_MIRROR)
fun displayState_virtualDeviceOwnedMirrorVirtualDisplay_connected() =
testScope.runTest {
- mSetFlagsRule.enableFlags(FLAG_INTERACTIVE_SCREEN_MIRROR)
whenever(virtualDeviceManager.isVirtualDeviceOwnedMirrorDisplay(anyInt()))
.thenReturn(true)
val value by lastValue()
@@ -183,9 +183,9 @@
}
@Test
+ @EnableFlags(FLAG_INTERACTIVE_SCREEN_MIRROR)
fun virtualDeviceOwnedMirrorVirtualDisplay_emitsConnectedDisplayAddition() =
testScope.runTest {
- mSetFlagsRule.enableFlags(FLAG_INTERACTIVE_SCREEN_MIRROR)
whenever(virtualDeviceManager.isVirtualDeviceOwnedMirrorDisplay(anyInt()))
.thenReturn(true)
var count = 0
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsClassicDebugTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsClassicDebugTest.kt
index a903d25..523127e0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsClassicDebugTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsClassicDebugTest.kt
@@ -21,6 +21,8 @@
import android.content.pm.PackageManager.NameNotFoundException
import android.content.res.Resources
import android.content.res.Resources.NotFoundException
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
import android.test.suitebuilder.annotation.SmallTest
import com.android.systemui.Flags.FLAG_SYSUI_TEAMFOOD
import com.android.systemui.SysuiTestCase
@@ -68,15 +70,14 @@
private val serverFlagReader = ServerFlagReaderFake()
private val teamfoodableFlagA = UnreleasedFlag(name = "a", namespace = "test", teamfood = true)
- private val teamfoodableFlagB = ReleasedFlag(name = "b", namespace = "test", teamfood = true)
+ private val releasedFlagB = ReleasedFlag(name = "b", namespace = "test")
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
- mSetFlagsRule.disableFlags(FLAG_SYSUI_TEAMFOOD)
flagMap.put(teamfoodableFlagA.name, teamfoodableFlagA)
- flagMap.put(teamfoodableFlagB.name, teamfoodableFlagB)
+ flagMap.put(releasedFlagB.name, releasedFlagB)
mFeatureFlagsClassicDebug =
FeatureFlagsClassicDebug(
flagManager,
@@ -99,7 +100,6 @@
@Test
fun readBooleanFlag() {
- // Remember that the TEAMFOOD flag is id#1 and has special behavior.
whenever(flagManager.readFlagValue<Boolean>(eq("3"), any())).thenReturn(true)
whenever(flagManager.readFlagValue<Boolean>(eq("4"), any())).thenReturn(false)
@@ -122,9 +122,10 @@
}
@Test
+ @DisableFlags(FLAG_SYSUI_TEAMFOOD)
fun teamFoodFlag_False() {
assertThat(mFeatureFlagsClassicDebug.isEnabled(teamfoodableFlagA)).isFalse()
- assertThat(mFeatureFlagsClassicDebug.isEnabled(teamfoodableFlagB)).isTrue()
+ assertThat(mFeatureFlagsClassicDebug.isEnabled(releasedFlagB)).isTrue()
// Regular boolean flags should still test the same.
// Only our teamfoodableFlag should change.
@@ -132,10 +133,10 @@
}
@Test
+ @EnableFlags(FLAG_SYSUI_TEAMFOOD)
fun teamFoodFlag_True() {
- mSetFlagsRule.enableFlags(FLAG_SYSUI_TEAMFOOD)
assertThat(mFeatureFlagsClassicDebug.isEnabled(teamfoodableFlagA)).isTrue()
- assertThat(mFeatureFlagsClassicDebug.isEnabled(teamfoodableFlagB)).isTrue()
+ assertThat(mFeatureFlagsClassicDebug.isEnabled(releasedFlagB)).isTrue()
// Regular boolean flags should still test the same.
// Only our teamfoodableFlag should change.
@@ -143,14 +144,14 @@
}
@Test
+ @EnableFlags(FLAG_SYSUI_TEAMFOOD)
fun teamFoodFlag_Overridden() {
whenever(flagManager.readFlagValue<Boolean>(eq(teamfoodableFlagA.name), any()))
.thenReturn(true)
- whenever(flagManager.readFlagValue<Boolean>(eq(teamfoodableFlagB.name), any()))
+ whenever(flagManager.readFlagValue<Boolean>(eq(releasedFlagB.name), any()))
.thenReturn(false)
- mSetFlagsRule.enableFlags(FLAG_SYSUI_TEAMFOOD)
assertThat(mFeatureFlagsClassicDebug.isEnabled(teamfoodableFlagA)).isTrue()
- assertThat(mFeatureFlagsClassicDebug.isEnabled(teamfoodableFlagB)).isFalse()
+ assertThat(mFeatureFlagsClassicDebug.isEnabled(releasedFlagB)).isFalse()
// Regular boolean flags should still test the same.
// Only our teamfoodableFlag should change.
@@ -400,6 +401,7 @@
}
@Test
+ @DisableFlags(FLAG_SYSUI_TEAMFOOD)
fun serverSide_OverrideUncached_NoRestart() {
// No one has read the flag, so it's not in the cache.
serverFlagReader.setFlagValue(
@@ -411,6 +413,7 @@
}
@Test
+ @DisableFlags(FLAG_SYSUI_TEAMFOOD)
fun serverSide_Override_Restarts() {
// Read it to put it in the cache.
mFeatureFlagsClassicDebug.isEnabled(teamfoodableFlagA)
@@ -423,6 +426,7 @@
}
@Test
+ @DisableFlags(FLAG_SYSUI_TEAMFOOD)
fun serverSide_RedundantOverride_NoRestart() {
// Read it to put it in the cache.
mFeatureFlagsClassicDebug.isEnabled(teamfoodableFlagA)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
index bf6d5c4..976dc5f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
@@ -43,7 +43,6 @@
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest
import com.android.systemui.power.domain.interactor.PowerInteractorFactory
import com.android.systemui.shade.data.repository.FakeShadeRepository
-import com.android.systemui.shade.domain.model.ShadeModel
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.mock
@@ -1329,12 +1328,8 @@
// GIVEN the keyguard is showing locked
keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)
runCurrent()
- shadeRepository.setShadeModel(
- ShadeModel(
- expansionAmount = .9f,
- isUserDragging = true,
- )
- )
+ shadeRepository.setLegacyShadeTracking(true)
+ shadeRepository.setLegacyShadeExpansion(.9f)
runCurrent()
// THEN a transition from LOCKSCREEN => PRIMARY_BOUNCER should occur
@@ -1350,12 +1345,8 @@
// WHEN the user stops dragging and shade is back to expanded
clearInvocations(transitionRepository)
runTransitionAndSetWakefulness(KeyguardState.LOCKSCREEN, KeyguardState.PRIMARY_BOUNCER)
- shadeRepository.setShadeModel(
- ShadeModel(
- expansionAmount = 1f,
- isUserDragging = false,
- )
- )
+ shadeRepository.setLegacyShadeTracking(false)
+ shadeRepository.setLegacyShadeExpansion(1f)
runCurrent()
// THEN a transition from PRIMARY_BOUNCER => LOCKSCREEN should occur
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt
index f8aa359..750693c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt
@@ -19,33 +19,20 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.shade.ShadeExpansionChangeEvent
-import com.android.systemui.shade.ShadeExpansionStateManager
-import com.android.systemui.shade.domain.model.ShadeModel
-import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.withArgCaptor
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when`
-import org.mockito.MockitoAnnotations
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidJUnit4::class)
class ShadeRepositoryImplTest : SysuiTestCase() {
- @Mock private lateinit var shadeExpansionStateManager: ShadeExpansionStateManager
private val testDispatcher = StandardTestDispatcher()
private val testScope = TestScope(testDispatcher)
@@ -53,57 +40,10 @@
@Before
fun setUp() {
- MockitoAnnotations.initMocks(this)
-
- underTest = ShadeRepositoryImpl(shadeExpansionStateManager)
- `when`(shadeExpansionStateManager.addExpansionListener(any()))
- .thenReturn(ShadeExpansionChangeEvent(0f, false, false, 0f))
+ underTest = ShadeRepositoryImpl()
}
@Test
- fun shadeExpansionChangeEvent() =
- testScope.runTest {
- var latest: ShadeModel? = null
- val job = underTest.shadeModel.onEach { latest = it }.launchIn(this)
- runCurrent()
- assertThat(latest?.expansionAmount).isEqualTo(0f)
- assertThat(latest?.isExpanded).isEqualTo(false)
- assertThat(latest?.isUserDragging).isEqualTo(false)
-
- val captor = withArgCaptor {
- verify(shadeExpansionStateManager).addExpansionListener(capture())
- }
-
- captor.onPanelExpansionChanged(
- ShadeExpansionChangeEvent(
- fraction = 1f,
- expanded = true,
- tracking = false,
- dragDownPxAmount = 0f,
- )
- )
- runCurrent()
- assertThat(latest?.expansionAmount).isEqualTo(1f)
- assertThat(latest?.isExpanded).isEqualTo(true)
- assertThat(latest?.isUserDragging).isEqualTo(false)
-
- captor.onPanelExpansionChanged(
- ShadeExpansionChangeEvent(
- fraction = .67f,
- expanded = false,
- tracking = true,
- dragDownPxAmount = 0f,
- )
- )
- runCurrent()
- assertThat(latest?.expansionAmount).isEqualTo(.67f)
- assertThat(latest?.isExpanded).isEqualTo(false)
- assertThat(latest?.isUserDragging).isEqualTo(true)
-
- job.cancel()
- }
-
- @Test
fun updateQsExpansion() =
testScope.runTest {
assertThat(underTest.qsExpansion.value).isEqualTo(0f)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
index b98dc00..a3cff87e6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
@@ -39,12 +39,15 @@
import androidx.test.filters.SmallTest;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.res.R;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.policy.HeadsUpManagerLogger;
+import com.android.systemui.util.settings.FakeGlobalSettings;
+import com.android.systemui.util.time.SystemClock;
+import com.android.systemui.util.time.SystemClockImpl;
import org.junit.After;
import org.junit.Before;
@@ -74,18 +77,26 @@
protected final Runnable mTestTimeoutRunnable = () -> mTimedOut = true;
protected Handler mTestHandler;
+ protected final FakeGlobalSettings mGlobalSettings = new FakeGlobalSettings();
+ protected final SystemClock mSystemClock = new SystemClockImpl();
protected boolean mTimedOut = false;
@Mock protected ExpandableNotificationRow mRow;
+ static {
+ assertThat(TEST_MINIMUM_DISPLAY_TIME).isLessThan(TEST_AUTO_DISMISS_TIME);
+ assertThat(TEST_AUTO_DISMISS_TIME).isLessThan(TEST_STICKY_AUTO_DISMISS_TIME);
+ assertThat(TEST_STICKY_AUTO_DISMISS_TIME).isLessThan(TEST_TIMEOUT_TIME);
+ }
+
private static class TestableAlertingNotificationManager extends AlertingNotificationManager {
private AlertEntry mLastCreatedEntry;
- private TestableAlertingNotificationManager(Handler handler) {
- super(new HeadsUpManagerLogger(logcatLogBuffer()), handler);
+ private TestableAlertingNotificationManager(Handler handler, SystemClock systemClock) {
+ super(new HeadsUpManagerLogger(logcatLogBuffer()), handler, systemClock);
mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME;
- mAutoDismissNotificationDecay = TEST_AUTO_DISMISS_TIME;
- mStickyDisplayTime = TEST_STICKY_AUTO_DISMISS_TIME;
+ mAutoDismissTime = TEST_AUTO_DISMISS_TIME;
+ mStickyForSomeTimeAutoDismissTime = TEST_STICKY_AUTO_DISMISS_TIME;
}
@Override
@@ -107,7 +118,7 @@
}
protected AlertingNotificationManager createAlertingNotificationManager() {
- return new TestableAlertingNotificationManager(mTestHandler);
+ return new TestableAlertingNotificationManager(mTestHandler, mSystemClock);
}
protected StatusBarNotification createSbn(int id, Notification n) {
@@ -167,10 +178,6 @@
@Before
public void setUp() {
mTestHandler = Handler.createAsync(Looper.myLooper());
-
- assertThat(TEST_MINIMUM_DISPLAY_TIME).isLessThan(TEST_AUTO_DISMISS_TIME);
- assertThat(TEST_AUTO_DISMISS_TIME).isLessThan(TEST_STICKY_AUTO_DISMISS_TIME);
- assertThat(TEST_STICKY_AUTO_DISMISS_TIME).isLessThan(TEST_TIMEOUT_TIME);
}
@After
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
index 8bc5e70..34c7b09 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
@@ -55,8 +55,10 @@
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.FlagsParameterization;
import android.provider.Settings;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.SparseArray;
@@ -96,12 +98,26 @@
import java.util.ArrayList;
import java.util.Collection;
+import java.util.List;
import java.util.concurrent.Executor;
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
+import platform.test.runner.parameterized.Parameters;
+
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(ParameterizedAndroidJunit4.class)
@TestableLooper.RunWithLooper
public class NotificationLockscreenUserManagerTest extends SysuiTestCase {
+
+ @Parameters(name = "{0}")
+ public static List<FlagsParameterization> getParams() {
+ return FlagsParameterization.allCombinationsOf(FLAG_ALLOW_PRIVATE_PROFILE);
+ }
+
+ public NotificationLockscreenUserManagerTest(FlagsParameterization flags) {
+ mSetFlagsRule.setFlagsParameterization(flags);
+ }
+
private static final int TEST_PROFILE_USERHANDLE = 12;
@Mock
private NotificationPresenter mPresenter;
@@ -762,8 +778,8 @@
}
@Test
+ @EnableFlags(FLAG_ALLOW_PRIVATE_PROFILE)
public void testProfileAvailabilityIntent() {
- mSetFlagsRule.enableFlags(FLAG_ALLOW_PRIVATE_PROFILE);
mLockscreenUserManager.mCurrentProfiles.clear();
assertEquals(0, mLockscreenUserManager.mCurrentProfiles.size());
mLockscreenUserManager.mCurrentProfiles.append(0, mock(UserInfo.class));
@@ -773,8 +789,8 @@
}
@Test
+ @EnableFlags(FLAG_ALLOW_PRIVATE_PROFILE)
public void testProfileUnAvailabilityIntent() {
- mSetFlagsRule.enableFlags(FLAG_ALLOW_PRIVATE_PROFILE);
mLockscreenUserManager.mCurrentProfiles.clear();
assertEquals(0, mLockscreenUserManager.mCurrentProfiles.size());
mLockscreenUserManager.mCurrentProfiles.append(0, mock(UserInfo.class));
@@ -784,8 +800,8 @@
}
@Test
+ @DisableFlags(FLAG_ALLOW_PRIVATE_PROFILE)
public void testManagedProfileAvailabilityIntent() {
- mSetFlagsRule.disableFlags(FLAG_ALLOW_PRIVATE_PROFILE);
mLockscreenUserManager.mCurrentProfiles.clear();
mLockscreenUserManager.mCurrentManagedProfiles.clear();
assertEquals(0, mLockscreenUserManager.mCurrentProfiles.size());
@@ -798,8 +814,8 @@
}
@Test
+ @DisableFlags(FLAG_ALLOW_PRIVATE_PROFILE)
public void testManagedProfileUnAvailabilityIntent() {
- mSetFlagsRule.disableFlags(FLAG_ALLOW_PRIVATE_PROFILE);
mLockscreenUserManager.mCurrentProfiles.clear();
mLockscreenUserManager.mCurrentManagedProfiles.clear();
assertEquals(0, mLockscreenUserManager.mCurrentProfiles.size());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt
index fa5fad0..255cf6f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt
@@ -15,11 +15,12 @@
*/
package com.android.systemui.statusbar.notification.collection.coordinator
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.flags.setFlagValue
import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
@@ -40,10 +41,9 @@
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
-import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations.initMocks
+import org.mockito.Mockito.`when` as whenever
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -66,12 +66,6 @@
fun setUp() {
initMocks(this)
entry = NotificationEntryBuilder().setSection(section).build()
- setUpWithFlags()
- }
-
- private fun setUpWithFlags(vararg flags: Pair<String, Boolean>) {
- flags.forEach { (name, value) -> mSetFlagsRule.setFlagValue(name, value) }
- reset(pipeline)
coordinator =
StackCoordinator(
groupExpansionManagerImpl,
@@ -86,15 +80,15 @@
}
@Test
+ @DisableFlags(NotificationIconContainerRefactor.FLAG_NAME)
fun testUpdateNotificationIcons() {
- setUpWithFlags(NotificationIconContainerRefactor.FLAG_NAME to false)
afterRenderListListener.onAfterRenderList(listOf(entry), stackController)
verify(notificationIconAreaController).updateNotificationIcons(eq(listOf(entry)))
}
@Test
+ @EnableFlags(NotificationIconContainerRefactor.FLAG_NAME)
fun testSetRenderedListOnInteractor() {
- setUpWithFlags(NotificationIconContainerRefactor.FLAG_NAME to true)
afterRenderListListener.onAfterRenderList(listOf(entry), stackController)
verify(renderListInteractor).setRenderedList(eq(listOf(entry)))
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterViewTest.java
index 22c5bae..57dac3a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterViewTest.java
@@ -16,12 +16,11 @@
package com.android.systemui.statusbar.notification.footer.ui.view;
+import static com.android.systemui.log.LogAssertKt.assertLogsWtf;
import static com.google.common.truth.Truth.assertThat;
-
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;
-
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
@@ -31,33 +30,47 @@
import static org.mockito.Mockito.verify;
import android.content.Context;
-import android.testing.AndroidTestingRunner;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.FlagsParameterization;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import androidx.test.filters.SmallTest;
-import com.android.systemui.Flags;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.res.R;
+import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.List;
+
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
+import platform.test.runner.parameterized.Parameters;
+
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(ParameterizedAndroidJunit4.class)
public class FooterViewTest extends SysuiTestCase {
+ @Parameters(name = "{0}")
+ public static List<FlagsParameterization> getFlags() {
+ return FlagsParameterization.allCombinationsOf(FooterViewRefactor.FLAG_NAME);
+ }
+
+ public FooterViewTest(FlagsParameterization flags) {
+ mSetFlagsRule.setFlagsParameterization(flags);
+ }
+
FooterView mView;
Context mSpyContext = spy(mContext);
@Before
public void setUp() {
- mSetFlagsRule.enableFlags(Flags.FLAG_NOTIFICATIONS_FOOTER_VIEW_REFACTOR);
-
mView = (FooterView) LayoutInflater.from(mSpyContext).inflate(
R.layout.status_bar_notification_footer, null, false);
mView.setAnimationDuration(0);
@@ -114,6 +127,7 @@
}
@Test
+ @EnableFlags(FooterViewRefactor.FLAG_NAME)
public void testSetClearAllButtonText_resourceOnlyFetchedOnce() {
int resId = R.string.clear_all_notifications_text;
mView.setClearAllButtonText(resId);
@@ -132,6 +146,16 @@
}
@Test
+ @DisableFlags(FooterViewRefactor.FLAG_NAME)
+ public void testSetClearAllButtonText_expectsFlagEnabled() {
+ clearInvocations(mSpyContext);
+ int resId = R.string.clear_all_notifications_text;
+ assertLogsWtf(()-> mView.setClearAllButtonText(resId));
+ verify(mSpyContext, never()).getString(anyInt());
+ }
+
+ @Test
+ @EnableFlags(FooterViewRefactor.FLAG_NAME)
public void testSetClearAllButtonDescription_resourceOnlyFetchedOnce() {
int resId = R.string.accessibility_clear_all;
mView.setClearAllButtonDescription(resId);
@@ -150,6 +174,16 @@
}
@Test
+ @DisableFlags(FooterViewRefactor.FLAG_NAME)
+ public void testSetClearAllButtonDescription_expectsFlagEnabled() {
+ clearInvocations(mSpyContext);
+ int resId = R.string.accessibility_clear_all;
+ assertLogsWtf(()-> mView.setClearAllButtonDescription(resId));
+ verify(mSpyContext, never()).getString(anyInt());
+ }
+
+ @Test
+ @EnableFlags(FooterViewRefactor.FLAG_NAME)
public void testSetMessageString_resourceOnlyFetchedOnce() {
int resId = R.string.unlock_to_see_notif_text;
mView.setMessageString(resId);
@@ -168,6 +202,16 @@
}
@Test
+ @DisableFlags(FooterViewRefactor.FLAG_NAME)
+ public void testSetMessageString_expectsFlagEnabled() {
+ clearInvocations(mSpyContext);
+ int resId = R.string.unlock_to_see_notif_text;
+ assertLogsWtf(()-> mView.setMessageString(resId));
+ verify(mSpyContext, never()).getString(anyInt());
+ }
+
+ @Test
+ @EnableFlags(FooterViewRefactor.FLAG_NAME)
public void testSetMessageIcon_resourceOnlyFetchedOnce() {
int resId = R.drawable.ic_friction_lock_closed;
mView.setMessageIcon(resId);
@@ -183,6 +227,15 @@
}
@Test
+ @DisableFlags(FooterViewRefactor.FLAG_NAME)
+ public void testSetMessageIcon_expectsFlagEnabled() {
+ clearInvocations(mSpyContext);
+ int resId = R.drawable.ic_friction_lock_closed;
+ assertLogsWtf(()-> mView.setMessageIcon(resId));
+ verify(mSpyContext, never()).getDrawable(anyInt());
+ }
+
+ @Test
public void testSetFooterLabelVisible() {
mView.setFooterLabelVisible(true);
assertThat(mView.findViewById(R.id.manage_text).getVisibility()).isEqualTo(View.GONE);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelTest.kt
index 0ba820f..8ab13f5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelTest.kt
@@ -16,9 +16,9 @@
package com.android.systemui.statusbar.notification.footer.ui.viewmodel
+import android.platform.test.annotations.EnableFlags
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
-import com.android.systemui.Flags
import com.android.systemui.SysUITestComponent
import com.android.systemui.SysUITestModule
import com.android.systemui.SysuiTestCase
@@ -38,6 +38,7 @@
import com.android.systemui.shade.data.repository.FakeShadeRepository
import com.android.systemui.statusbar.notification.collection.render.NotifStats
import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationListRepository
+import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor
import com.android.systemui.statusbar.notification.row.ui.viewmodel.ActivatableNotificationViewModelModule
import com.android.systemui.statusbar.phone.DozeParameters
import com.android.systemui.user.domain.interactor.HeadlessSystemUserModeModule
@@ -55,6 +56,7 @@
@RunWith(AndroidTestingRunner::class)
@SmallTest
+@EnableFlags(FooterViewRefactor.FLAG_NAME)
class FooterViewModelTest : SysuiTestCase() {
private lateinit var footerViewModel: FooterViewModel
@@ -106,8 +108,6 @@
fun setUp() {
MockitoAnnotations.initMocks(this)
- mSetFlagsRule.enableFlags(Flags.FLAG_NOTIFICATIONS_FOOTER_VIEW_REFACTOR)
-
// The underTest in the component is Optional, because that matches the provider we
// currently have for the footer view model.
footerViewModel = testComponent.underTest.get()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt
index 7361f6b..7ed3312 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.interruption
+import android.platform.test.annotations.DisableFlags
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
@@ -34,11 +35,8 @@
@SmallTest
@RunWith(AndroidTestingRunner::class)
+@DisableFlags(VisualInterruptionRefactor.FLAG_NAME)
class NotificationInterruptStateProviderWrapperTest : VisualInterruptionDecisionProviderTestBase() {
- init {
- mSetFlagsRule.disableFlags(VisualInterruptionRefactor.FLAG_NAME)
- }
-
override val provider by lazy {
NotificationInterruptStateProviderWrapper(
NotificationInterruptStateProviderImpl(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImplTest.kt
index d2c046c..da68d9c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImplTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.interruption
+import android.platform.test.annotations.EnableFlags
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.statusbar.notification.collection.NotificationEntry
@@ -27,11 +28,8 @@
@SmallTest
@RunWith(AndroidTestingRunner::class)
+@EnableFlags(VisualInterruptionRefactor.FLAG_NAME)
class VisualInterruptionDecisionProviderImplTest : VisualInterruptionDecisionProviderTestBase() {
- init {
- mSetFlagsRule.enableFlags(VisualInterruptionRefactor.FLAG_NAME)
- }
-
override val provider by lazy {
VisualInterruptionDecisionProviderImpl(
ambientDisplayConfiguration,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt
index f00abc9..21774aa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt
@@ -19,10 +19,10 @@
package com.android.systemui.statusbar.notification.stack.ui.viewmodel
import android.app.NotificationManager.Policy
+import android.platform.test.annotations.EnableFlags
import android.provider.Settings
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import com.android.systemui.Flags
import com.android.systemui.SysUITestComponent
import com.android.systemui.SysUITestModule
import com.android.systemui.SysuiTestCase
@@ -41,6 +41,7 @@
import com.android.systemui.shade.data.repository.FakeShadeRepository
import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationListRepository
import com.android.systemui.statusbar.notification.data.repository.setActiveNotifs
+import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor
import com.android.systemui.statusbar.notification.footer.ui.viewmodel.FooterViewModelModule
import com.android.systemui.statusbar.notification.row.ui.viewmodel.ActivatableNotificationViewModelModule
import com.android.systemui.statusbar.policy.FakeConfigurationController
@@ -59,6 +60,7 @@
@SmallTest
@RunWith(AndroidJUnit4::class)
+@EnableFlags(FooterViewRefactor.FLAG_NAME)
class NotificationListViewModelTest : SysuiTestCase() {
@SysUISingleton
@@ -104,8 +106,6 @@
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
-
- mSetFlagsRule.enableFlags(Flags.FLAG_NOTIFICATIONS_FOOTER_VIEW_REFACTOR)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
index 48b95d4..37ee322 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
@@ -46,6 +46,8 @@
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.HeadsUpManagerLogger;
import com.android.systemui.util.kotlin.JavaAdapter;
+import com.android.systemui.util.settings.GlobalSettings;
+import com.android.systemui.util.time.SystemClock;
import org.junit.After;
import org.junit.Before;
@@ -87,6 +89,8 @@
KeyguardBypassController keyguardBypassController,
ConfigurationController configurationController,
Handler handler,
+ GlobalSettings globalSettings,
+ SystemClock systemClock,
AccessibilityManagerWrapper accessibilityManagerWrapper,
UiEventLogger uiEventLogger,
JavaAdapter javaAdapter,
@@ -101,13 +105,15 @@
visualStabilityProvider,
configurationController,
handler,
+ globalSettings,
+ systemClock,
accessibilityManagerWrapper,
uiEventLogger,
javaAdapter,
shadeInteractor
);
mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME;
- mAutoDismissNotificationDecay = TEST_AUTO_DISMISS_TIME;
+ mAutoDismissTime = TEST_AUTO_DISMISS_TIME;
}
}
@@ -121,6 +127,8 @@
mBypassController,
mConfigurationController,
mTestHandler,
+ mGlobalSettings,
+ mSystemClock,
mAccessibilityManagerWrapper,
mUiEventLogger,
mJavaAdapter,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImplTest.java
index c24d9ad..b3708ba 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImplTest.java
@@ -20,6 +20,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.platform.test.annotations.DisableFlags;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -49,6 +50,7 @@
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
+@DisableFlags(NotificationIconContainerRefactor.FLAG_NAME)
public class LegacyNotificationIconAreaControllerImplTest extends SysuiTestCase {
@Mock
@@ -83,7 +85,6 @@
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
- mSetFlagsRule.disableFlags(NotificationIconContainerRefactor.FLAG_NAME);
mController = new LegacyNotificationIconAreaControllerImpl(
mContext,
mStatusBarStateController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
index bbdc9ce..1dafcc4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
@@ -15,12 +15,13 @@
package com.android.systemui.statusbar.phone;
import static android.view.Display.DEFAULT_DISPLAY;
-
import static com.android.systemui.statusbar.notification.interruption.VisualInterruptionType.BUBBLE;
import static com.android.systemui.statusbar.notification.interruption.VisualInterruptionType.PEEK;
import static com.android.systemui.statusbar.notification.interruption.VisualInterruptionType.PULSE;
-
import static org.junit.Assert.assertFalse;
+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.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
@@ -30,14 +31,14 @@
import android.app.Notification;
import android.app.PendingIntent;
import android.app.StatusBarManager;
-import android.platform.test.flag.junit.SetFlagsRule;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import androidx.test.filters.SmallTest;
-import com.android.systemui.Flags;
import com.android.systemui.InitController;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.ActivityStarter;
@@ -64,6 +65,7 @@
import com.android.systemui.statusbar.notification.interruption.VisualInterruptionCondition;
import com.android.systemui.statusbar.notification.interruption.VisualInterruptionDecisionProvider;
import com.android.systemui.statusbar.notification.interruption.VisualInterruptionFilter;
+import com.android.systemui.statusbar.notification.interruption.VisualInterruptionRefactor;
import com.android.systemui.statusbar.notification.interruption.VisualInterruptionType;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
@@ -73,7 +75,6 @@
import com.android.systemui.statusbar.policy.KeyguardStateController;
import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -100,10 +101,6 @@
private final KeyguardStateController mKeyguardStateController =
mock(KeyguardStateController.class);
- @Rule
- public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(
- SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT);
-
@Before
public void setup() {
mCommandQueue = new CommandQueue(mContext, new FakeDisplayTracker(mContext));
@@ -114,29 +111,46 @@
mDependency.injectMockDependency(NotificationShadeWindowController.class);
when(mNotificationAlertsInteractor.areNotificationAlertsEnabled()).thenReturn(true);
+
+ createPresenter();
+ if (VisualInterruptionRefactor.isEnabled()) {
+ verifyAndCaptureSuppressors();
+ } else {
+ verifyAndCaptureLegacySuppressor();
+ }
}
@Test
+ @DisableFlags(VisualInterruptionRefactor.FLAG_NAME)
public void testInit_refactorDisabled() {
- ensureRefactorDisabledState();
+ assertFalse(VisualInterruptionRefactor.isEnabled());
+ assertNull(mAlertsDisabledCondition);
+ assertNull(mVrModeCondition);
+ assertNull(mNeedsRedactionFilter);
+ assertNull(mPanelsDisabledCondition);
+ assertNotNull(mInterruptSuppressor);
}
@Test
+ @EnableFlags(VisualInterruptionRefactor.FLAG_NAME)
public void testInit_refactorEnabled() {
- ensureRefactorEnabledState();
+ assertTrue(VisualInterruptionRefactor.isEnabled());
+ assertNotNull(mAlertsDisabledCondition);
+ assertNotNull(mVrModeCondition);
+ assertNotNull(mNeedsRedactionFilter);
+ assertNotNull(mPanelsDisabledCondition);
+ assertNull(mInterruptSuppressor);
}
@Test
+ @DisableFlags(VisualInterruptionRefactor.FLAG_NAME)
public void testNoSuppressHeadsUp_default_refactorDisabled() {
- ensureRefactorDisabledState();
-
assertFalse(mInterruptSuppressor.suppressAwakeHeadsUp(createNotificationEntry()));
}
@Test
+ @EnableFlags(VisualInterruptionRefactor.FLAG_NAME)
public void testNoSuppressHeadsUp_default_refactorEnabled() {
- ensureRefactorEnabledState();
-
assertFalse(mAlertsDisabledCondition.shouldSuppress());
assertFalse(mVrModeCondition.shouldSuppress());
assertFalse(mNeedsRedactionFilter.shouldSuppress(createNotificationEntry()));
@@ -144,9 +158,8 @@
}
@Test
+ @DisableFlags(VisualInterruptionRefactor.FLAG_NAME)
public void testSuppressHeadsUp_disabledStatusBar_refactorDisabled() {
- ensureRefactorDisabledState();
-
mCommandQueue.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_EXPAND, 0,
false /* animate */);
TestableLooper.get(this).processAllMessages();
@@ -156,9 +169,8 @@
}
@Test
+ @EnableFlags(VisualInterruptionRefactor.FLAG_NAME)
public void testSuppressHeadsUp_disabledStatusBar_refactorEnabled() {
- ensureRefactorEnabledState();
-
mCommandQueue.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_EXPAND, 0,
false /* animate */);
TestableLooper.get(this).processAllMessages();
@@ -168,9 +180,8 @@
}
@Test
+ @DisableFlags(VisualInterruptionRefactor.FLAG_NAME)
public void testSuppressHeadsUp_disabledNotificationShade_refactorDisabled() {
- ensureRefactorDisabledState();
-
mCommandQueue.disable(DEFAULT_DISPLAY, 0, StatusBarManager.DISABLE2_NOTIFICATION_SHADE,
false /* animate */);
TestableLooper.get(this).processAllMessages();
@@ -180,9 +191,8 @@
}
@Test
+ @EnableFlags(VisualInterruptionRefactor.FLAG_NAME)
public void testSuppressHeadsUp_disabledNotificationShade_refactorEnabled() {
- ensureRefactorEnabledState();
-
mCommandQueue.disable(DEFAULT_DISPLAY, 0, StatusBarManager.DISABLE2_NOTIFICATION_SHADE,
false /* animate */);
TestableLooper.get(this).processAllMessages();
@@ -192,9 +202,8 @@
}
@Test
+ @EnableFlags(VisualInterruptionRefactor.FLAG_NAME)
public void testPanelsDisabledConditionSuppressesPeek() {
- ensureRefactorEnabledState();
-
final Set<VisualInterruptionType> types = mPanelsDisabledCondition.getTypes();
assertTrue(types.contains(PEEK));
assertFalse(types.contains(PULSE));
@@ -202,9 +211,8 @@
}
@Test
+ @DisableFlags(VisualInterruptionRefactor.FLAG_NAME)
public void testNoSuppressHeadsUp_FSI_nonOccludedKeyguard_refactorDisabled() {
- ensureRefactorDisabledState();
-
when(mKeyguardStateController.isShowing()).thenReturn(true);
when(mKeyguardStateController.isOccluded()).thenReturn(false);
@@ -212,9 +220,8 @@
}
@Test
+ @EnableFlags(VisualInterruptionRefactor.FLAG_NAME)
public void testNoSuppressHeadsUp_FSI_nonOccludedKeyguard_refactorEnabled() {
- ensureRefactorEnabledState();
-
when(mKeyguardStateController.isShowing()).thenReturn(true);
when(mKeyguardStateController.isOccluded()).thenReturn(false);
@@ -227,9 +234,8 @@
}
@Test
+ @DisableFlags(VisualInterruptionRefactor.FLAG_NAME)
public void testSuppressInterruptions_vrMode_refactorDisabled() {
- ensureRefactorDisabledState();
-
mStatusBarNotificationPresenter.mVrMode = true;
assertTrue("Vr mode should suppress interruptions",
@@ -237,9 +243,8 @@
}
@Test
+ @EnableFlags(VisualInterruptionRefactor.FLAG_NAME)
public void testSuppressInterruptions_vrMode_refactorEnabled() {
- ensureRefactorEnabledState();
-
mStatusBarNotificationPresenter.mVrMode = true;
assertTrue("Vr mode should suppress interruptions", mVrModeCondition.shouldSuppress());
@@ -251,9 +256,8 @@
}
@Test
+ @DisableFlags(VisualInterruptionRefactor.FLAG_NAME)
public void testSuppressInterruptions_statusBarAlertsDisabled_refactorDisabled() {
- ensureRefactorDisabledState();
-
when(mNotificationAlertsInteractor.areNotificationAlertsEnabled()).thenReturn(false);
assertTrue("When alerts aren't enabled, interruptions are suppressed",
@@ -261,9 +265,8 @@
}
@Test
+ @EnableFlags(VisualInterruptionRefactor.FLAG_NAME)
public void testSuppressInterruptions_statusBarAlertsDisabled_refactorEnabled() {
- ensureRefactorEnabledState();
-
when(mNotificationAlertsInteractor.areNotificationAlertsEnabled()).thenReturn(false);
assertTrue("When alerts aren't enabled, interruptions are suppressed",
@@ -349,18 +352,6 @@
mInterruptSuppressor = suppressorCaptor.getValue();
}
- private void ensureRefactorDisabledState() {
- mSetFlagsRule.disableFlags(Flags.FLAG_VISUAL_INTERRUPTIONS_REFACTOR);
- createPresenter();
- verifyAndCaptureLegacySuppressor();
- }
-
- private void ensureRefactorEnabledState() {
- mSetFlagsRule.enableFlags(Flags.FLAG_VISUAL_INTERRUPTIONS_REFACTOR);
- createPresenter();
- verifyAndCaptureSuppressors();
- }
-
private NotificationEntry createNotificationEntry() {
return new NotificationEntryBuilder()
.setPkg("a")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
index 09dc1e5..89842d6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
@@ -16,9 +16,10 @@
package com.android.systemui.statusbar.pipeline.shared.ui.viewmodel
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
import androidx.test.filters.SmallTest
import com.android.systemui.CoroutineTestScopeModule
-import com.android.systemui.Flags
import com.android.systemui.SysUITestComponent
import com.android.systemui.SysUITestModule
import com.android.systemui.SysuiTestCase
@@ -29,6 +30,7 @@
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.log.assertLogsWtf
import com.android.systemui.runTest
import com.android.systemui.statusbar.data.model.StatusBarMode
import com.android.systemui.statusbar.data.repository.FakeStatusBarModeRepository
@@ -37,14 +39,15 @@
import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationListRepository
import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore
import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel
+import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor
import com.google.common.truth.Truth.assertThat
import dagger.BindsInstance
import dagger.Component
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
-import org.junit.Before
import org.junit.Test
@SmallTest
@@ -79,11 +82,6 @@
testScope = CoroutineTestScopeModule(TestScope(UnconfinedTestDispatcher())),
)
- @Before
- fun setUp() {
- mSetFlagsRule.enableFlags(Flags.FLAG_NOTIFICATIONS_LIVE_DATA_STORE_REFACTOR)
- }
-
@Test
fun isTransitioningFromLockscreenToOccluded_started_isTrue() =
testComponent.runTest {
@@ -347,6 +345,7 @@
}
@Test
+ @EnableFlags(NotificationsLiveDataStoreRefactor.FLAG_NAME)
fun areNotificationsLightsOut_lowProfileWithNotifications_true() =
testComponent.runTest {
statusBarModeRepository.defaultDisplay.statusBarMode.value =
@@ -360,6 +359,7 @@
}
@Test
+ @EnableFlags(NotificationsLiveDataStoreRefactor.FLAG_NAME)
fun areNotificationsLightsOut_lowProfileWithoutNotifications_false() =
testComponent.runTest {
statusBarModeRepository.defaultDisplay.statusBarMode.value =
@@ -373,6 +373,7 @@
}
@Test
+ @EnableFlags(NotificationsLiveDataStoreRefactor.FLAG_NAME)
fun areNotificationsLightsOut_defaultStatusBarModeWithoutNotifications_false() =
testComponent.runTest {
statusBarModeRepository.defaultDisplay.statusBarMode.value = StatusBarMode.TRANSPARENT
@@ -385,6 +386,7 @@
}
@Test
+ @EnableFlags(NotificationsLiveDataStoreRefactor.FLAG_NAME)
fun areNotificationsLightsOut_defaultStatusBarModeWithNotifications_false() =
testComponent.runTest {
statusBarModeRepository.defaultDisplay.statusBarMode.value = StatusBarMode.TRANSPARENT
@@ -396,6 +398,16 @@
assertThat(actual).isFalse()
}
+ @Test
+ @DisableFlags(NotificationsLiveDataStoreRefactor.FLAG_NAME)
+ fun areNotificationsLightsOut_requiresFlagEnabled() =
+ testComponent.runTest {
+ assertLogsWtf {
+ val flow = underTest.areNotificationsLightsOut(DISPLAY_ID)
+ assertThat(flow).isEqualTo(emptyFlow<Boolean>())
+ }
+ }
+
private fun activeNotificationsStore(notifications: List<ActiveNotificationModel>) =
ActiveNotificationsStore.Builder()
.apply { notifications.forEach(::addIndividualNotif) }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
similarity index 96%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
index 4f3f564..2940c39 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
@@ -34,7 +34,6 @@
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import static org.mockito.MockitoAnnotations.initMocks;
import android.app.Notification;
import android.app.PendingIntent;
@@ -57,17 +56,25 @@
import com.android.systemui.statusbar.AlertingNotificationManagerTest;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.util.settings.GlobalSettings;
+import com.android.systemui.util.time.SystemClock;
import org.junit.After;
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;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
-public class HeadsUpManagerTest extends AlertingNotificationManagerTest {
+public class BaseHeadsUpManagerTest extends AlertingNotificationManagerTest {
+ @Rule
+ public MockitoRule rule = MockitoJUnit.rule();
+
private static final int TEST_TOUCH_ACCEPTANCE_TIME = 200;
private static final int TEST_A11Y_AUTO_DISMISS_TIME = 1_000;
private static final int TEST_A11Y_TIMEOUT_TIME = 3_000;
@@ -76,17 +83,33 @@
private final HeadsUpManagerLogger mLogger = spy(new HeadsUpManagerLogger(logcatLogBuffer()));
@Mock private AccessibilityManagerWrapper mAccessibilityMgr;
+ static {
+ assertThat(TEST_MINIMUM_DISPLAY_TIME).isLessThan(TEST_AUTO_DISMISS_TIME);
+ assertThat(TEST_AUTO_DISMISS_TIME).isLessThan(TEST_STICKY_AUTO_DISMISS_TIME);
+ assertThat(TEST_STICKY_AUTO_DISMISS_TIME).isLessThan(TEST_A11Y_AUTO_DISMISS_TIME);
+
+ assertThat(TEST_TOUCH_ACCEPTANCE_TIME + TEST_AUTO_DISMISS_TIME).isLessThan(
+ TEST_TIMEOUT_TIME);
+ assertThat(TEST_TOUCH_ACCEPTANCE_TIME + TEST_STICKY_AUTO_DISMISS_TIME).isLessThan(
+ TEST_TIMEOUT_TIME);
+ assertThat(TEST_TOUCH_ACCEPTANCE_TIME + TEST_A11Y_AUTO_DISMISS_TIME).isLessThan(
+ TEST_A11Y_TIMEOUT_TIME);
+ }
+
private final class TestableHeadsUpManager extends BaseHeadsUpManager {
TestableHeadsUpManager(Context context,
HeadsUpManagerLogger logger,
Handler handler,
+ GlobalSettings globalSettings,
+ SystemClock systemClock,
AccessibilityManagerWrapper accessibilityManagerWrapper,
UiEventLogger uiEventLogger) {
- super(context, logger, handler, accessibilityManagerWrapper, uiEventLogger);
+ super(context, logger, handler, globalSettings, systemClock,
+ accessibilityManagerWrapper, uiEventLogger);
mTouchAcceptanceDelay = TEST_TOUCH_ACCEPTANCE_TIME;
mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME;
- mAutoDismissNotificationDecay = TEST_AUTO_DISMISS_TIME;
- mStickyDisplayTime = TEST_STICKY_AUTO_DISMISS_TIME;
+ mAutoDismissTime = TEST_AUTO_DISMISS_TIME;
+ mStickyForSomeTimeAutoDismissTime = TEST_STICKY_AUTO_DISMISS_TIME;
}
// The following are only implemented by HeadsUpManagerPhone. If you need them, use that.
@@ -160,8 +183,8 @@
}
private BaseHeadsUpManager createHeadsUpManager() {
- return new TestableHeadsUpManager(mContext, mLogger, mTestHandler, mAccessibilityMgr,
- mUiEventLoggerFake);
+ return new TestableHeadsUpManager(mContext, mLogger, mTestHandler, mGlobalSettings,
+ mSystemClock, mAccessibilityMgr, mUiEventLoggerFake);
}
@Override
@@ -214,19 +237,7 @@
@Before
@Override
public void setUp() {
- initMocks(this);
super.setUp();
-
- assertThat(TEST_MINIMUM_DISPLAY_TIME).isLessThan(TEST_AUTO_DISMISS_TIME);
- assertThat(TEST_AUTO_DISMISS_TIME).isLessThan(TEST_STICKY_AUTO_DISMISS_TIME);
- assertThat(TEST_STICKY_AUTO_DISMISS_TIME).isLessThan(TEST_A11Y_AUTO_DISMISS_TIME);
-
- assertThat(TEST_TOUCH_ACCEPTANCE_TIME + TEST_AUTO_DISMISS_TIME).isLessThan(
- TEST_TIMEOUT_TIME);
- assertThat(TEST_TOUCH_ACCEPTANCE_TIME + TEST_STICKY_AUTO_DISMISS_TIME).isLessThan(
- TEST_TIMEOUT_TIME);
- assertThat(TEST_TOUCH_ACCEPTANCE_TIME + TEST_A11Y_AUTO_DISMISS_TIME).isLessThan(
- TEST_A11Y_TIMEOUT_TIME);
}
@After
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt
index 0327087..4642b47 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt
@@ -40,9 +40,6 @@
private val currentTime: () -> Long,
) : AuthenticationRepository {
- private val _isAutoConfirmFeatureEnabled = MutableStateFlow(false)
- override val isAutoConfirmFeatureEnabled: StateFlow<Boolean> =
- _isAutoConfirmFeatureEnabled.asStateFlow()
override val authenticationChallengeResult = MutableSharedFlow<Boolean>()
override val hintedPinLength: Int = HINTING_PIN_LENGTH
@@ -53,6 +50,12 @@
override val throttling: MutableStateFlow<AuthenticationThrottlingModel?> =
MutableStateFlow(null)
+ override val hasThrottlingOccurred = MutableStateFlow(false)
+
+ private val _isAutoConfirmFeatureEnabled = MutableStateFlow(false)
+ override val isAutoConfirmFeatureEnabled: StateFlow<Boolean> =
+ _isAutoConfirmFeatureEnabled.asStateFlow()
+
private val _authenticationMethod =
MutableStateFlow<AuthenticationMethodModel>(DEFAULT_AUTHENTICATION_METHOD)
override val authenticationMethod: StateFlow<AuthenticationMethodModel> =
@@ -107,6 +110,9 @@
override suspend fun setThrottleDuration(durationMs: Int) {
throttlingEndTimestamp = if (durationMs > 0) currentTime() + durationMs else 0
+ if (durationMs > 0) {
+ hasThrottlingOccurred.value = true
+ }
}
override suspend fun checkCredential(
@@ -128,6 +134,7 @@
return if (
isSuccessful || failedAttemptCount < MAX_FAILED_AUTH_TRIES_BEFORE_THROTTLING - 1
) {
+ hasThrottlingOccurred.value = false
AuthenticationResultModel(
isSuccessful = isSuccessful,
throttleDurationMs = 0,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/log/LogAssert.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/log/LogAssert.kt
new file mode 100644
index 0000000..10f9346
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/log/LogAssert.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.log
+
+import android.util.Log
+import android.util.Log.TerribleFailureHandler
+import junit.framework.Assert
+
+/**
+ * Assert that the given block makes a call to Log.wtf
+ *
+ * @return the details of the log
+ */
+fun assertLogsWtf(
+ message: String = "Expected Log.wtf to be called",
+ allowMultiple: Boolean = false,
+ loggingBlock: () -> Unit,
+): TerribleFailureLog {
+ var caught: TerribleFailureLog? = null
+ var count = 0
+ val newHandler = TerribleFailureHandler { tag, failure, system ->
+ if (caught == null) {
+ caught = TerribleFailureLog(tag, failure, system)
+ }
+ count++
+ }
+ val oldHandler = Log.setWtfHandler(newHandler)
+ try {
+ loggingBlock()
+ } finally {
+ Log.setWtfHandler(oldHandler)
+ }
+ Assert.assertNotNull(message, caught)
+ if (!allowMultiple && count != 1) {
+ Assert.fail("Unexpectedly caught Log.Wtf $count times; expected only 1. First: $caught")
+ }
+ return caught!!
+}
+
+@JvmOverloads
+fun assertLogsWtf(
+ message: String = "Expected Log.wtf to be called",
+ allowMultiple: Boolean = false,
+ loggingRunnable: Runnable,
+): TerribleFailureLog =
+ assertLogsWtf(message = message, allowMultiple = allowMultiple) { loggingRunnable.run() }
+
+/** The data passed to [TerribleFailureHandler.onTerribleFailure] */
+data class TerribleFailureLog(
+ val tag: String,
+ val failure: Log.TerribleFailure,
+ val system: Boolean
+)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt
index 9c10848..f7005ab 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt
@@ -18,21 +18,14 @@
package com.android.systemui.shade.data.repository
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.shade.domain.model.ShadeModel
import dagger.Binds
import dagger.Module
import javax.inject.Inject
-import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.StateFlow
/** Fake implementation of [ShadeRepository] */
@SysUISingleton
class FakeShadeRepository @Inject constructor() : ShadeRepository {
-
- private val _shadeModel = MutableStateFlow(ShadeModel())
- override val shadeModel: Flow<ShadeModel> = _shadeModel
-
private val _qsExpansion = MutableStateFlow(0f)
override val qsExpansion = _qsExpansion
@@ -114,10 +107,6 @@
_legacyIsClosing.value = isClosing
}
- fun setShadeModel(model: ShadeModel) {
- _shadeModel.value = model
- }
-
override fun setQsExpansion(qsExpansion: Float) {
_qsExpansion.value = qsExpansion
}
diff --git a/ravenwood/framework-minus-apex-ravenwood-policies.txt b/ravenwood/framework-minus-apex-ravenwood-policies.txt
index c9069e5..f5e4af5 100644
--- a/ravenwood/framework-minus-apex-ravenwood-policies.txt
+++ b/ravenwood/framework-minus-apex-ravenwood-policies.txt
@@ -3,6 +3,9 @@
# Keep all AIDL interfaces
class :aidl stubclass
+# Keep all feature flag implementations
+class :feature_flags stubclass
+
# Collections
class android.util.ArrayMap stubclass
class android.util.ArraySet stubclass
diff --git a/ravenwood/ravenwood-annotation-allowed-classes.txt b/ravenwood/ravenwood-annotation-allowed-classes.txt
index 831fce1..e3f1932 100644
--- a/ravenwood/ravenwood-annotation-allowed-classes.txt
+++ b/ravenwood/ravenwood-annotation-allowed-classes.txt
@@ -88,6 +88,8 @@
android.graphics.Rect
android.graphics.RectF
+android.content.ContentProvider
+
com.android.server.LocalServices
com.android.internal.os.SomeArgs
diff --git a/ravenwood/test-authors.md b/ravenwood/test-authors.md
index 5adef53..de05777 100644
--- a/ravenwood/test-authors.md
+++ b/ravenwood/test-authors.md
@@ -71,10 +71,10 @@
Once you’ve defined your test, you can use typical commands to execute it locally:
```
-$ atest MyTestsRavenwood
+$ atest --host MyTestsRavenwood
```
-> **Note:** There's a known bug where `atest` currently requires a connected device to run Ravenwood tests, but that device isn't used for testing.
+> **Note:** There's a known bug where `atest` currently requires a connected device to run Ravenwood tests, but that device isn't used for testing. Using the `--host` argument above is a way to bypass this requirement until bug #312525698 is fixed.
You can also run your new tests automatically via `TEST_MAPPING` rules like this:
@@ -89,6 +89,27 @@
}
```
+## Strategies for feature flags
+
+Ravenwood supports writing tests against logic that uses feature flags through the existing `SetFlagsRule` infrastructure maintained by the feature flagging team:
+
+```
+import android.platform.test.flag.junit.SetFlagsRule;
+
+@RunWith(AndroidJUnit4.class)
+public class MyCodeTest {
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
+ @Test
+ public void testEnabled() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_MY_FLAG);
+ // verify test logic that depends on flag being enabled
+ }
+```
+
+This naturally composes together well with any `RavenwoodRule` that your test may need.
+
## Strategies for migration/bivalent tests
Ravenwood aims to support tests that are written in a “bivalent” way, where the same test code can run on both a real Android device and under a Ravenwood environment.
diff --git a/services/core/Android.bp b/services/core/Android.bp
index b4cf34e..20a3b9a 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -154,7 +154,6 @@
static_libs: [
"android.frameworks.location.altitude-V1-java", // AIDL
- "android.frameworks.vibrator-V1-java", // AIDL
"android.hardware.authsecret-V1.0-java",
"android.hardware.authsecret-V1-java",
"android.hardware.boot-V1.0-java", // HIDL
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 4bb9f4f..c436c72 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -127,6 +127,7 @@
"/system/bin/mediaserver",
"/system/bin/netd",
"/system/bin/sdcard",
+ "/system/bin/servicemanager",
"/system/bin/surfaceflinger",
"/system/bin/vold",
"media.extractor", // system/bin/mediaextractor
diff --git a/services/core/java/com/android/server/appop/DiscreteRegistry.java b/services/core/java/com/android/server/appop/DiscreteRegistry.java
index e91b7e8..b1a12f7 100644
--- a/services/core/java/com/android/server/appop/DiscreteRegistry.java
+++ b/services/core/java/com/android/server/appop/DiscreteRegistry.java
@@ -37,6 +37,7 @@
import static android.app.AppOpsManager.OP_RECEIVE_AMBIENT_TRIGGER_AUDIO;
import static android.app.AppOpsManager.OP_RECEIVE_SANDBOX_TRIGGER_AUDIO;
import static android.app.AppOpsManager.OP_RECORD_AUDIO;
+import static android.app.AppOpsManager.OP_RESERVED_FOR_TESTING;
import static android.app.AppOpsManager.flagsToString;
import static android.app.AppOpsManager.getUidStateName;
@@ -136,7 +137,7 @@
private static final String DEFAULT_DISCRETE_OPS = OP_FINE_LOCATION + "," + OP_COARSE_LOCATION
+ "," + OP_CAMERA + "," + OP_RECORD_AUDIO + "," + OP_PHONE_CALL_MICROPHONE + ","
+ OP_PHONE_CALL_CAMERA + "," + OP_RECEIVE_AMBIENT_TRIGGER_AUDIO + ","
- + OP_RECEIVE_SANDBOX_TRIGGER_AUDIO;
+ + OP_RECEIVE_SANDBOX_TRIGGER_AUDIO + "," + OP_RESERVED_FOR_TESTING;
private static final long DEFAULT_DISCRETE_HISTORY_CUTOFF = Duration.ofDays(7).toMillis();
private static final long MAXIMUM_DISCRETE_HISTORY_CUTOFF = Duration.ofDays(30).toMillis();
private static final long DEFAULT_DISCRETE_HISTORY_QUANTIZATION =
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 49095ce..42c2548 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -1432,7 +1432,7 @@
}
private void unlockKeystore(int userId, SyntheticPassword sp) {
- Authorization.onLockScreenEvent(false, userId, sp.deriveKeyStorePassword(), null);
+ Authorization.onDeviceUnlocked(userId, sp.deriveKeyStorePassword());
}
@VisibleForTesting /** Note: this method is overridden in unit tests */
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index d172d3f..eac4fc0 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -865,21 +865,19 @@
mDeviceLockedForUser.put(userId, locked);
}
if (changed) {
- dispatchDeviceLocked(userId, locked);
- Authorization.onLockScreenEvent(locked, userId, null,
- getBiometricSids(userId));
+ notifyTrustAgentsOfDeviceLockState(userId, locked);
+ notifyKeystoreOfDeviceLockState(userId, locked);
// Also update the user's profiles who have unified challenge, since they
// share the same unlocked state (see {@link #isDeviceLocked(int)})
for (int profileHandle : mUserManager.getEnabledProfileIds(userId)) {
if (mLockPatternUtils.isManagedProfileWithUnifiedChallenge(profileHandle)) {
- Authorization.onLockScreenEvent(locked, profileHandle, null,
- getBiometricSids(profileHandle));
+ notifyKeystoreOfDeviceLockState(profileHandle, locked);
}
}
}
}
- private void dispatchDeviceLocked(int userId, boolean isLocked) {
+ private void notifyTrustAgentsOfDeviceLockState(int userId, boolean isLocked) {
for (int i = 0; i < mActiveAgents.size(); i++) {
AgentInfo agent = mActiveAgents.valueAt(i);
if (agent.userId == userId) {
@@ -892,6 +890,17 @@
}
}
+ private void notifyKeystoreOfDeviceLockState(int userId, boolean isLocked) {
+ if (isLocked) {
+ Authorization.onDeviceLocked(userId, getBiometricSids(userId));
+ } else {
+ // Notify Keystore that the device is now unlocked for the user. Note that for unlocks
+ // with LSKF, this is redundant with the call from LockSettingsService which provides
+ // the password. However, for unlocks with biometric or trust agent, this is required.
+ Authorization.onDeviceUnlocked(userId, /* password= */ null);
+ }
+ }
+
private void dispatchEscrowTokenActivatedLocked(long handle, int userId) {
for (int i = 0; i < mActiveAgents.size(); i++) {
AgentInfo agent = mActiveAgents.valueAt(i);
@@ -1425,10 +1434,10 @@
}
}
- private long[] getBiometricSids(int userId) {
+ private @NonNull long[] getBiometricSids(int userId) {
BiometricManager biometricManager = mContext.getSystemService(BiometricManager.class);
if (biometricManager == null) {
- return null;
+ return new long[0];
}
return biometricManager.getAuthenticatorIds(userId);
}
@@ -1680,8 +1689,7 @@
mDeviceLockedForUser.put(userId, locked);
}
- Authorization.onLockScreenEvent(locked, userId, null,
- getBiometricSids(userId));
+ notifyKeystoreOfDeviceLockState(userId, locked);
if (locked) {
try {
diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerService.java b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
index 7862f58..e501b9d 100644
--- a/services/core/java/com/android/server/uri/UriGrantsManagerService.java
+++ b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
@@ -146,17 +146,31 @@
mGrantedUriPermissions = new SparseArray<>();
private UriGrantsManagerService() {
- this(SystemServiceManager.ensureSystemDir());
+ this(SystemServiceManager.ensureSystemDir(), "uri-grants");
}
- private UriGrantsManagerService(File systemDir) {
+ private UriGrantsManagerService(File systemDir, String commitTag) {
mH = new H(IoThread.get().getLooper());
- mGrantFile = new AtomicFile(new File(systemDir, "urigrants.xml"), "uri-grants");
+ final File file = new File(systemDir, "urigrants.xml");
+ mGrantFile = (commitTag != null) ? new AtomicFile(file, commitTag) : new AtomicFile(file);
}
@VisibleForTesting
static UriGrantsManagerService createForTest(File systemDir) {
- final UriGrantsManagerService service = new UriGrantsManagerService(systemDir);
+ final UriGrantsManagerService service = new UriGrantsManagerService(systemDir, null) {
+ @VisibleForTesting
+ protected int checkUidPermission(String permission, int uid) {
+ // Tests have no permission granted
+ return PackageManager.PERMISSION_DENIED;
+ }
+
+ @VisibleForTesting
+ protected int checkComponentPermission(String permission, int uid, int owningUid,
+ boolean exported) {
+ // Tests have no permission granted
+ return PackageManager.PERMISSION_DENIED;
+ }
+ };
service.mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
service.mPmInternal = LocalServices.getService(PackageManagerInternal.class);
return service;
@@ -202,7 +216,8 @@
}
}
- private int checkUidPermission(String permission, int uid) {
+ @VisibleForTesting
+ protected int checkUidPermission(String permission, int uid) {
try {
return AppGlobals.getPackageManager().checkUidPermission(permission, uid);
} catch (RemoteException e) {
@@ -210,6 +225,12 @@
}
}
+ @VisibleForTesting
+ protected int checkComponentPermission(String permission, int uid, int owningUid,
+ boolean exported) {
+ return ActivityManager.checkComponentPermission(permission, uid, owningUid, exported);
+ }
+
/**
* Grant uri permissions to the specified app.
*
@@ -916,7 +937,7 @@
ProviderInfo pi, GrantUri grantUri, int uid, final int modeFlags) {
if (DEBUG) Slog.v(TAG, "checkHoldingPermissions: uri=" + grantUri + " uid=" + uid);
if (UserHandle.getUserId(uid) != grantUri.sourceUserId) {
- if (ActivityManager.checkComponentPermission(INTERACT_ACROSS_USERS, uid, -1, true)
+ if (checkComponentPermission(INTERACT_ACROSS_USERS, uid, -1, true)
!= PERMISSION_GRANTED) {
return false;
}
@@ -1340,7 +1361,7 @@
if (uid == Process.SYSTEM_UID || uid == Process.ROOT_UID) {
return true;
}
- return ActivityManager.checkComponentPermission(
+ return checkComponentPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
uid, /* owningUid = */-1, /* exported = */ true)
== PackageManager.PERMISSION_GRANTED;
diff --git a/services/core/java/com/android/server/utils/OWNERS b/services/core/java/com/android/server/utils/OWNERS
index be91611d..fbc0b56 100644
--- a/services/core/java/com/android/server/utils/OWNERS
+++ b/services/core/java/com/android/server/utils/OWNERS
@@ -10,3 +10,8 @@
per-file Watcher.java = shombert@google.com
per-file EventLogger.java = file:/platform/frameworks/av:/media/janitors/media_solutions_OWNERS
per-file EventLogger.java = jmtrivi@google.com
+
+# Bug component : 158088 = per-file AnrTimer*.java
+per-file AnrTimer*.java = file:/PERFORMANCE_OWNERS
+
+per-file flags.aconfig = file:/PERFORMANCE_OWNERS
diff --git a/services/core/java/com/android/server/vibrator/VibratorControlService.java b/services/core/java/com/android/server/vibrator/VibratorControlService.java
deleted file mode 100644
index 2eeb903..0000000
--- a/services/core/java/com/android/server/vibrator/VibratorControlService.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.vibrator;
-
-import android.annotation.NonNull;
-import android.annotation.SuppressLint;
-import android.frameworks.vibrator.IVibratorControlService;
-import android.frameworks.vibrator.IVibratorController;
-import android.frameworks.vibrator.VibrationParam;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.Slog;
-
-import java.util.Objects;
-
-/**
- * Implementation of {@link IVibratorControlService} which allows the registration of
- * {@link IVibratorController} to set and receive vibration params.
- *
- * @hide
- */
-public final class VibratorControlService extends IVibratorControlService.Stub {
- private static final String TAG = "VibratorControlService";
-
- private final VibratorControllerHolder mVibratorControllerHolder;
- private final Object mLock;
-
- public VibratorControlService(VibratorControllerHolder vibratorControllerHolder, Object lock) {
- mVibratorControllerHolder = vibratorControllerHolder;
- mLock = lock;
- }
-
- @Override
- public void registerVibratorController(IVibratorController controller)
- throws RemoteException {
- synchronized (mLock) {
- mVibratorControllerHolder.setVibratorController(controller);
- }
- }
-
- @Override
- public void unregisterVibratorController(@NonNull IVibratorController controller)
- throws RemoteException {
- Objects.requireNonNull(controller);
-
- synchronized (mLock) {
- if (mVibratorControllerHolder.getVibratorController() == null) {
- Slog.w(TAG, "Received request to unregister IVibratorController = "
- + controller + ", but no controller was previously registered. Request "
- + "Ignored.");
- return;
- }
- if (!Objects.equals(mVibratorControllerHolder.getVibratorController().asBinder(),
- controller.asBinder())) {
- Slog.wtf(TAG, "Failed to unregister IVibratorController. The provided "
- + "controller doesn't match the registered one. " + this);
- return;
- }
- mVibratorControllerHolder.setVibratorController(null);
- }
- }
-
- @Override
- public void setVibrationParams(
- @SuppressLint("ArrayReturn") VibrationParam[] params, IVibratorController token)
- throws RemoteException {
- // TODO(b/305939964): Add set vibration implementation.
- }
-
- @Override
- public void clearVibrationParams(int types, IVibratorController token) throws RemoteException {
- // TODO(b/305939964): Add clear vibration implementation.
- }
-
- @Override
- public void onRequestVibrationParamsComplete(
- IBinder requestToken, @SuppressLint("ArrayReturn") VibrationParam[] result)
- throws RemoteException {
- // TODO(305942827): Cache the vibration params in VibrationScaler
- }
-
- @Override
- public int getInterfaceVersion() throws RemoteException {
- return this.VERSION;
- }
-
- @Override
- public String getInterfaceHash() throws RemoteException {
- return this.HASH;
- }
-}
diff --git a/services/core/java/com/android/server/vibrator/VibratorControllerHolder.java b/services/core/java/com/android/server/vibrator/VibratorControllerHolder.java
deleted file mode 100644
index 63e69db..0000000
--- a/services/core/java/com/android/server/vibrator/VibratorControllerHolder.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.vibrator;
-
-import android.annotation.NonNull;
-import android.frameworks.vibrator.IVibratorController;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.Slog;
-
-/**
- * Holder class for {@link IVibratorController}.
- *
- * @hide
- */
-public final class VibratorControllerHolder implements IBinder.DeathRecipient {
- private static final String TAG = "VibratorControllerHolder";
-
- private IVibratorController mVibratorController;
-
- public IVibratorController getVibratorController() {
- return mVibratorController;
- }
-
- /**
- * Sets the {@link IVibratorController} in {@link VibratorControllerHolder} to the new
- * controller. This will also take care of registering and unregistering death notifications
- * for the cached {@link IVibratorController}.
- */
- public void setVibratorController(IVibratorController controller) {
- try {
- if (mVibratorController != null) {
- mVibratorController.asBinder().unlinkToDeath(this, 0);
- }
- mVibratorController = controller;
- if (mVibratorController != null) {
- mVibratorController.asBinder().linkToDeath(this, 0);
- }
- } catch (RemoteException e) {
- Slog.wtf(TAG, "Failed to set IVibratorController: " + this, e);
- }
- }
-
- @Override
- public void binderDied(@NonNull IBinder deadBinder) {
- if (deadBinder == mVibratorController.asBinder()) {
- setVibratorController(null);
- }
- }
-
- @Override
- public void binderDied() {
- // Should not be used as binderDied(IBinder who) is overridden.
- Slog.wtf(TAG, "binderDied() called unexpectedly.");
- }
-}
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index d5044d9..7d4bd3b 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -53,7 +53,6 @@
import android.os.VibrationAttributes;
import android.os.VibrationEffect;
import android.os.VibratorInfo;
-import android.os.vibrator.Flags;
import android.os.vibrator.PrebakedSegment;
import android.os.vibrator.VibrationEffectSegment;
import android.os.vibrator.VibratorInfoFactory;
@@ -88,13 +87,10 @@
import java.util.function.Consumer;
import java.util.function.Function;
-
/** System implementation of {@link IVibratorManagerService}. */
public class VibratorManagerService extends IVibratorManagerService.Stub {
private static final String TAG = "VibratorManagerService";
private static final String EXTERNAL_VIBRATOR_SERVICE = "external_vibrator_service";
- private static final String VIBRATOR_CONTROL_SERVICE =
- "android.frameworks.vibrator.IVibratorControlService/default";
private static final boolean DEBUG = false;
private static final VibrationAttributes DEFAULT_ATTRIBUTES =
new VibrationAttributes.Builder().build();
@@ -273,10 +269,6 @@
context.registerReceiver(mIntentReceiver, filter, Context.RECEIVER_NOT_EXPORTED);
injector.addService(EXTERNAL_VIBRATOR_SERVICE, new ExternalVibratorService());
- if (Flags.adaptiveHapticsEnabled()) {
- injector.addService(VIBRATOR_CONTROL_SERVICE,
- new VibratorControlService(new VibratorControllerHolder(), mLock));
- }
}
/** Finish initialization at boot phase {@link SystemService#PHASE_SYSTEM_SERVICES_READY}. */
@@ -411,9 +403,13 @@
@Override // Binder call
public void performHapticFeedback(
- int uid, int deviceId, String opPkg, int constant, boolean always, String reason,
- IBinder token) {
- performHapticFeedbackInternal(uid, deviceId, opPkg, constant, always, reason, token);
+ int uid, int deviceId, String opPkg, int constant, boolean always, String reason) {
+ // Note that the `performHapticFeedback` method does not take a token argument from the
+ // caller, and instead, uses this service as the token. This is to mitigate performance
+ // impact that would otherwise be caused due to marshal latency. Haptic feedback effects are
+ // short-lived, so we don't need to cancel when the process dies.
+ performHapticFeedbackInternal(
+ uid, deviceId, opPkg, constant, always, reason, /* token= */ this);
}
/**
diff --git a/services/core/jni/OWNERS b/services/core/jni/OWNERS
index 0e45f61..061fe0f 100644
--- a/services/core/jni/OWNERS
+++ b/services/core/jni/OWNERS
@@ -30,3 +30,6 @@
per-file com_android_server_vibrator_* = file:/services/core/java/com/android/server/vibrator/OWNERS
per-file com_android_server_am_CachedAppOptimizer.cpp = timmurray@google.com, edgararriaga@google.com, dualli@google.com, carmenjackson@google.com, philipcuadra@google.com
per-file com_android_server_companion_virtual_InputController.cpp = file:/services/companion/java/com/android/server/companion/virtual/OWNERS
+
+# Bug component : 158088 = per-file com_android_server_utils_AnrTimer*.java
+per-file com_android_server_utils_AnrTimer*.java = file:/PERFORMANCE_OWNERS
diff --git a/services/manifest_services.xml b/services/manifest_services.xml
index e2fdfe9..7638915 100644
--- a/services/manifest_services.xml
+++ b/services/manifest_services.xml
@@ -4,14 +4,4 @@
<version>1</version>
<fqname>IAltitudeService/default</fqname>
</hal>
- <hal format="aidl">
- <name>android.frameworks.vibrator</name>
- <version>1</version>
- <fqname>IVibratorController/default</fqname>
- </hal>
- <hal format="aidl">
- <name>android.frameworks.vibrator</name>
- <version>1</version>
- <fqname>IVibratorControlService/default</fqname>
- </hal>
</manifest>
diff --git a/services/midi/java/com/android/server/midi/MidiService.java b/services/midi/java/com/android/server/midi/MidiService.java
index 39aaab2..a212812 100644
--- a/services/midi/java/com/android/server/midi/MidiService.java
+++ b/services/midi/java/com/android/server/midi/MidiService.java
@@ -31,6 +31,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.Property;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.res.Resources;
@@ -1396,16 +1397,20 @@
XmlResourceParser parser = null;
try {
- parser = serviceInfo.loadXmlMetaData(mPackageManager,
- MidiDeviceService.SERVICE_INTERFACE);
- if (parser == null) return;
+ if (serviceInfo == null) {
+ Log.w(TAG, "Skipping null service info");
+ return;
+ }
// ignore virtual device servers that do not require the correct permission
if (!android.Manifest.permission.BIND_MIDI_DEVICE_SERVICE.equals(
serviceInfo.permission)) {
- Log.w(TAG, "Skipping MIDI device service " + serviceInfo.packageName
- + ": it does not require the permission "
- + android.Manifest.permission.BIND_MIDI_DEVICE_SERVICE);
+ return;
+ }
+ parser = serviceInfo.loadXmlMetaData(mPackageManager,
+ MidiDeviceService.SERVICE_INTERFACE);
+ if (parser == null) {
+ Log.w(TAG, "loading xml metadata failed");
return;
}
@@ -1533,21 +1538,14 @@
XmlResourceParser parser = null;
try {
- ComponentName componentName = new ComponentName(serviceInfo.packageName,
- serviceInfo.name);
- int resId = mPackageManager.getProperty(MidiUmpDeviceService.SERVICE_INTERFACE,
- componentName).getResourceId();
- Resources resources = mPackageManager.getResourcesForApplication(
- serviceInfo.packageName);
- parser = resources.getXml(resId);
- if (parser == null) return;
+ if (serviceInfo == null) {
+ Log.w(TAG, "Skipping null service info");
+ return;
+ }
// ignore virtual device servers that do not require the correct permission
if (!android.Manifest.permission.BIND_MIDI_DEVICE_SERVICE.equals(
serviceInfo.permission)) {
- Log.w(TAG, "Skipping MIDI device service " + serviceInfo.packageName
- + ": it does not require the permission "
- + android.Manifest.permission.BIND_MIDI_DEVICE_SERVICE);
return;
}
@@ -1557,6 +1555,31 @@
return;
}
+ ComponentName componentName = new ComponentName(serviceInfo.packageName,
+ serviceInfo.name);
+ Property property = mPackageManager.getProperty(MidiUmpDeviceService.SERVICE_INTERFACE,
+ componentName);
+ if (property == null) {
+ Log.w(TAG, "Getting MidiUmpDeviceService property failed");
+ return;
+ }
+ int resId = property.getResourceId();
+ if (resId == 0) {
+ Log.w(TAG, "Getting MidiUmpDeviceService resourceId failed");
+ return;
+ }
+ Resources resources = mPackageManager.getResourcesForApplication(
+ serviceInfo.packageName);
+ if (resources == null) {
+ Log.w(TAG, "Getting resource failed " + serviceInfo.packageName);
+ return;
+ }
+ parser = resources.getXml(resId);
+ if (parser == null) {
+ Log.w(TAG, "Getting XML failed " + resId);
+ return;
+ }
+
Bundle properties = null;
int numPorts = 0;
boolean isPrivate = false;
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 2ece8c7..9b84190 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -79,6 +79,7 @@
"coretests-aidl",
"securebox",
"flag-junit",
+ "ravenwood-junit",
],
libs: [
@@ -140,6 +141,23 @@
resource_zips: [":FrameworksServicesTests_apks_as_resources"],
}
+android_ravenwood_test {
+ name: "FrameworksServicesTestsRavenwood",
+ libs: [
+ "android.test.mock",
+ ],
+ static_libs: [
+ "androidx.annotation_annotation",
+ "androidx.test.rules",
+ "mockito_ravenwood",
+ "services.core",
+ ],
+ srcs: [
+ "src/com/android/server/uri/**/*.java",
+ ],
+ auto_gen_config: true,
+}
+
java_library {
name: "servicestests-core-utils",
srcs: [
diff --git a/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java
index e418d2f..769ec5f 100644
--- a/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java
@@ -57,17 +57,22 @@
import android.net.Uri;
import android.os.Process;
import android.os.UserHandle;
+import android.platform.test.ravenwood.RavenwoodRule;
import android.util.ArraySet;
import androidx.test.InstrumentationRegistry;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import java.util.Arrays;
import java.util.Set;
public class UriGrantsManagerServiceTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
private UriGrantsMockContext mContext;
private UriGrantsManagerInternal mService;
@@ -79,7 +84,7 @@
@Before
public void setUp() throws Exception {
- mContext = new UriGrantsMockContext(InstrumentationRegistry.getContext());
+ mContext = new UriGrantsMockContext();
mService = UriGrantsManagerService.createForTest(mContext.getFilesDir()).getLocalService();
}
diff --git a/services/tests/servicestests/src/com/android/server/uri/UriGrantsMockContext.java b/services/tests/servicestests/src/com/android/server/uri/UriGrantsMockContext.java
index 7eb6c97..4c11de09 100644
--- a/services/tests/servicestests/src/com/android/server/uri/UriGrantsMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/uri/UriGrantsMockContext.java
@@ -21,11 +21,7 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-import android.annotation.NonNull;
import android.app.ActivityManagerInternal;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.ContextWrapper;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
@@ -33,18 +29,19 @@
import android.content.pm.PathPermission;
import android.content.pm.ProviderInfo;
import android.net.Uri;
-import android.os.FileUtils;
import android.os.PatternMatcher;
import android.os.Process;
import android.os.UserHandle;
-import android.test.mock.MockContentResolver;
+import android.test.mock.MockContext;
import android.test.mock.MockPackageManager;
import com.android.server.LocalServices;
import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
-public class UriGrantsMockContext extends ContextWrapper {
+public class UriGrantsMockContext extends MockContext {
static final String TAG = "UriGrants";
static final int FLAG_READ = Intent.FLAG_GRANT_READ_URI_PERMISSION;
@@ -98,19 +95,14 @@
private final File mDir;
private final MockPackageManager mPackage;
- private final MockContentResolver mResolver;
final ActivityManagerInternal mAmInternal;
final PackageManagerInternal mPmInternal;
- public UriGrantsMockContext(@NonNull Context base) {
- super(base);
- mDir = new File(base.getFilesDir(), TAG);
- mDir.mkdirs();
- FileUtils.deleteContents(mDir);
+ public UriGrantsMockContext() throws IOException {
+ mDir = Files.createTempDirectory(TAG).toFile();
mPackage = new MockPackageManager();
- mResolver = new MockContentResolver(this);
mAmInternal = mock(ActivityManagerInternal.class);
LocalServices.removeServiceForTest(ActivityManagerInternal.class);
@@ -239,11 +231,6 @@
}
@Override
- public ContentResolver getContentResolver() {
- return mResolver;
- }
-
- @Override
public File getFilesDir() {
return mDir;
}
diff --git a/services/tests/servicestests/src/com/android/server/uri/UriPermissionTest.java b/services/tests/servicestests/src/com/android/server/uri/UriPermissionTest.java
index 07005a9..4d4f5ed 100644
--- a/services/tests/servicestests/src/com/android/server/uri/UriPermissionTest.java
+++ b/services/tests/servicestests/src/com/android/server/uri/UriPermissionTest.java
@@ -35,12 +35,18 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import android.platform.test.ravenwood.RavenwoodRule;
+
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
public class UriPermissionTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
@Mock
private UriGrantsManagerInternal mService;
diff --git a/services/tests/servicestests/src/com/android/server/utils/OWNERS b/services/tests/servicestests/src/com/android/server/utils/OWNERS
index 5e24828..f5b19a1 100644
--- a/services/tests/servicestests/src/com/android/server/utils/OWNERS
+++ b/services/tests/servicestests/src/com/android/server/utils/OWNERS
@@ -1,2 +1,5 @@
per-file EventLoggerTest.java = file:/platform/frameworks/av:/media/janitors/media_solutions_OWNERS
per-file EventLoggerTest.java = jmtrivi@google.com
+
+# Bug component : 158088 = per-file AnrTimer*.java
+per-file AnrTimer*.java = file:/PERFORMANCE_OWNERS
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibratorControlServiceTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibratorControlServiceTest.java
deleted file mode 100644
index 49efd1b..0000000
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibratorControlServiceTest.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.vibrator;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.os.RemoteException;
-
-import org.junit.Before;
-import org.junit.Test;
-
-public class VibratorControlServiceTest {
-
- private VibratorControlService mVibratorControlService;
- private final Object mLock = new Object();
-
- @Before
- public void setUp() throws Exception {
- mVibratorControlService = new VibratorControlService(new VibratorControllerHolder(), mLock);
- }
-
- @Test
- public void testRegisterVibratorController() throws RemoteException {
- FakeVibratorController fakeController = new FakeVibratorController();
- mVibratorControlService.registerVibratorController(fakeController);
-
- assertThat(fakeController.isLinkedToDeath).isTrue();
- }
-
- @Test
- public void testUnregisterVibratorController_providingTheRegisteredController_performsRequest()
- throws RemoteException {
- FakeVibratorController fakeController = new FakeVibratorController();
- mVibratorControlService.registerVibratorController(fakeController);
- mVibratorControlService.unregisterVibratorController(fakeController);
- assertThat(fakeController.isLinkedToDeath).isFalse();
- }
-
- @Test
- public void testUnregisterVibratorController_providingAnInvalidController_ignoresRequest()
- throws RemoteException {
- FakeVibratorController fakeController1 = new FakeVibratorController();
- FakeVibratorController fakeController2 = new FakeVibratorController();
- mVibratorControlService.registerVibratorController(fakeController1);
-
- mVibratorControlService.unregisterVibratorController(fakeController2);
- assertThat(fakeController1.isLinkedToDeath).isTrue();
- }
-}
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibratorControllerHolderTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibratorControllerHolderTest.java
deleted file mode 100644
index 79abe21..0000000
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibratorControllerHolderTest.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.vibrator;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.os.RemoteException;
-
-import org.junit.Before;
-import org.junit.Test;
-
-public class VibratorControllerHolderTest {
-
- private final FakeVibratorController mFakeVibratorController = new FakeVibratorController();
- private VibratorControllerHolder mVibratorControllerHolder;
-
- @Before
- public void setUp() throws Exception {
- mVibratorControllerHolder = new VibratorControllerHolder();
- }
-
- @Test
- public void testSetVibratorController_linksVibratorControllerToDeath() throws RemoteException {
- mVibratorControllerHolder.setVibratorController(mFakeVibratorController);
- assertThat(mVibratorControllerHolder.getVibratorController())
- .isEqualTo(mFakeVibratorController);
- assertThat(mFakeVibratorController.isLinkedToDeath).isTrue();
- }
-
- @Test
- public void testSetVibratorController_setControllerToNull_unlinksVibratorControllerToDeath()
- throws RemoteException {
- mVibratorControllerHolder.setVibratorController(mFakeVibratorController);
- mVibratorControllerHolder.setVibratorController(null);
- assertThat(mFakeVibratorController.isLinkedToDeath).isFalse();
- assertThat(mVibratorControllerHolder.getVibratorController()).isNull();
- }
-
- @Test
- public void testBinderDied_withValidController_unlinksVibratorControllerToDeath()
- throws RemoteException {
- mVibratorControllerHolder.setVibratorController(mFakeVibratorController);
- mVibratorControllerHolder.binderDied(mFakeVibratorController);
- assertThat(mFakeVibratorController.isLinkedToDeath).isFalse();
- assertThat(mVibratorControllerHolder.getVibratorController()).isNull();
- }
-
- @Test
- public void testBinderDied_withInvalidController_ignoresRequest()
- throws RemoteException {
- mVibratorControllerHolder.setVibratorController(mFakeVibratorController);
- FakeVibratorController imposterVibratorController = new FakeVibratorController();
- mVibratorControllerHolder.binderDied(imposterVibratorController);
- assertThat(mFakeVibratorController.isLinkedToDeath).isTrue();
- assertThat(mVibratorControllerHolder.getVibratorController())
- .isEqualTo(mFakeVibratorController);
- }
-}
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
index a105649..4e9bbe0 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
@@ -307,10 +307,9 @@
@Override
void addService(String name, IBinder service) {
- if (service instanceof VibratorManagerService.ExternalVibratorService) {
- mExternalVibratorService =
- (VibratorManagerService.ExternalVibratorService) service;
- }
+ Object serviceInstance = service;
+ mExternalVibratorService =
+ (VibratorManagerService.ExternalVibratorService) serviceInstance;
}
HapticFeedbackVibrationProvider createHapticFeedbackVibrationProvider(
@@ -1399,6 +1398,17 @@
}
@Test
+ public void performHapticFeedback_usesServiceAsToken() throws Exception {
+ VibratorManagerService service = createSystemReadyService();
+
+ HalVibration vibration =
+ performHapticFeedbackAndWaitUntilFinished(
+ service, HapticFeedbackConstants.SCROLL_TICK, /* always= */ true);
+
+ assertTrue(vibration.callerToken == service);
+ }
+
+ @Test
public void vibrate_withIntensitySettings_appliesSettingsToScaleVibrations() throws Exception {
int defaultNotificationIntensity =
mVibrator.getDefaultVibrationIntensity(VibrationAttributes.USAGE_NOTIFICATION);
diff --git a/services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorController.java b/services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorController.java
deleted file mode 100644
index 7e23587..0000000
--- a/services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorController.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.vibrator;
-
-import android.annotation.NonNull;
-import android.frameworks.vibrator.IVibratorController;
-import android.os.IBinder;
-import android.os.RemoteException;
-
-/**
- * Provides a fake implementation of {@link android.frameworks.vibrator.IVibratorController} for
- * testing.
- */
-public final class FakeVibratorController extends IVibratorController.Stub {
-
- public boolean isLinkedToDeath = false;
-
- @Override
- public void requestVibrationParams(int i, long l, IBinder iBinder) throws RemoteException {
-
- }
-
- @Override
- public int getInterfaceVersion() throws RemoteException {
- return 0;
- }
-
- @Override
- public String getInterfaceHash() throws RemoteException {
- return null;
- }
-
- @Override
- public void linkToDeath(@NonNull DeathRecipient recipient, int flags) {
- super.linkToDeath(recipient, flags);
- isLinkedToDeath = true;
- }
-
- @Override
- public boolean unlinkToDeath(@NonNull DeathRecipient recipient, int flags) {
- isLinkedToDeath = false;
- return super.unlinkToDeath(recipient, flags);
- }
-}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AndroidHeuristicsFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AndroidHeuristicsFilter.kt
index 8354d98..8ca4732 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AndroidHeuristicsFilter.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AndroidHeuristicsFilter.kt
@@ -23,12 +23,16 @@
class AndroidHeuristicsFilter(
private val classes: ClassNodes,
val aidlPolicy: FilterPolicyWithReason?,
+ val featureFlagsPolicy: FilterPolicyWithReason?,
fallback: OutputFilter
) : DelegatingFilter(fallback) {
override fun getPolicyForClass(className: String): FilterPolicyWithReason {
if (aidlPolicy != null && classes.isAidlClass(className)) {
return aidlPolicy
}
+ if (featureFlagsPolicy != null && classes.isFeatureFlagsClass(className)) {
+ return featureFlagsPolicy
+ }
return super.getPolicyForClass(className)
}
}
@@ -40,4 +44,16 @@
return hasClass(className) &&
hasClass("$className\$Stub") &&
hasClass("$className\$Stub\$Proxy")
-}
\ No newline at end of file
+}
+
+/**
+ * @return if a given class "seems like" an feature flags class.
+ */
+private fun ClassNodes.isFeatureFlagsClass(className: String): Boolean {
+ // Matches template classes defined here:
+ // https://cs.android.com/android/platform/superproject/+/master:build/make/tools/aconfig/templates/
+ return className.endsWith("/Flags")
+ || className.endsWith("/FeatureFlags")
+ || className.endsWith("/FeatureFlagsImpl")
+ || className.endsWith("/FakeFeatureFlagsImpl");
+}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
index b4354ba..d38a6e3 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
@@ -62,7 +62,8 @@
var lineNo = 0
- var aidlPolicy: FilterPolicy? = null
+ var aidlPolicy: FilterPolicyWithReason? = null
+ var featureFlagsPolicy: FilterPolicyWithReason? = null
try {
BufferedReader(FileReader(filename)).use { reader ->
@@ -130,7 +131,15 @@
throw ParseException(
"Policy for AIDL classes already defined")
}
- aidlPolicy = policy
+ aidlPolicy = policy.withReason("$FILTER_REASON (AIDL)")
+ }
+ SpecialClass.FeatureFlags -> {
+ if (featureFlagsPolicy != null) {
+ throw ParseException(
+ "Policy for feature flags already defined")
+ }
+ featureFlagsPolicy =
+ policy.withReason("$FILTER_REASON (feature flags)")
}
}
}
@@ -196,10 +205,10 @@
}
var ret: OutputFilter = imf
- aidlPolicy?.let { policy ->
+ if (aidlPolicy != null || featureFlagsPolicy != null) {
log.d("AndroidHeuristicsFilter enabled")
ret = AndroidHeuristicsFilter(
- classes, policy.withReason("$FILTER_REASON (AIDL)"), imf)
+ classes, aidlPolicy, featureFlagsPolicy, imf)
}
return ret
}
@@ -208,6 +217,7 @@
private enum class SpecialClass {
NotSpecial,
Aidl,
+ FeatureFlags,
}
private fun resolveSpecialClass(className: String): SpecialClass {
@@ -216,6 +226,7 @@
}
when (className.lowercase()) {
":aidl" -> return SpecialClass.Aidl
+ ":feature_flags" -> return SpecialClass.FeatureFlags
}
throw ParseException("Invalid special class name \"$className\"")
}