summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apex/jobscheduler/framework/java/android/app/job/JobInfo.java5
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java8
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java34
-rw-r--r--core/api/current.txt1
-rw-r--r--core/api/system-current.txt2
-rw-r--r--core/java/android/content/pm/PermissionInfo.java3
-rw-r--r--core/java/android/hardware/biometrics/BiometricPrompt.java9
-rw-r--r--core/java/android/hardware/biometrics/CryptoObject.java2
-rw-r--r--core/java/android/hardware/biometrics/flags.aconfig7
-rw-r--r--core/java/android/provider/Settings.java24
-rw-r--r--core/java/android/view/SurfaceControl.java2
-rw-r--r--core/res/res/values/attrs_manifest.xml4
-rw-r--r--libs/WindowManager/Shell/tests/flicker/appcompat/AndroidTestTemplate.xml8
-rw-r--r--libs/WindowManager/Shell/tests/flicker/bubble/AndroidTestTemplate.xml8
-rw-r--r--libs/WindowManager/Shell/tests/flicker/pip/AndroidTestTemplate.xml8
-rw-r--r--libs/WindowManager/Shell/tests/flicker/pip/csuiteDefaultTemplate.xml31
-rw-r--r--libs/WindowManager/Shell/tests/flicker/service/AndroidTestTemplate.xml8
-rw-r--r--libs/WindowManager/Shell/tests/flicker/splitscreen/AndroidTestTemplate.xml8
-rw-r--r--libs/input/PointerController.cpp28
-rw-r--r--libs/input/PointerController.h25
-rw-r--r--packages/SettingsProvider/res/values/defaults.xml8
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java19
-rw-r--r--packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java1
-rw-r--r--packages/SystemUI/aconfig/systemui.aconfig8
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt348
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt3
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt23
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt12
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt5
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt6
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/aconfig/AConfigModule.kt35
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalRepository.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsClassicDebug.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/Flags.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/SideFpsProgressBarViewBinder.kt19
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt43
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt23
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/shared/model/ObservableTransitionState.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractorTest.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsClassicDebugTest.kt8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt107
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/scene/shared/flag/SceneContainerFlagsTest.kt1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt27
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt10
-rw-r--r--services/core/java/com/android/server/am/flags.aconfig7
-rw-r--r--services/core/java/com/android/server/power/stats/BatteryStatsImpl.java38
-rw-r--r--services/core/java/com/android/server/storage/StorageSessionController.java6
-rw-r--r--services/core/jni/com_android_server_input_InputManagerService.cpp83
-rw-r--r--services/permission/java/com/android/server/permission/access/AccessCheckingService.kt102
-rw-r--r--services/permission/java/com/android/server/permission/access/AccessPolicy.kt13
-rw-r--r--services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt30
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java37
64 files changed, 883 insertions, 486 deletions
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
index 646e05c50a76..9961c4fdf3f7 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
@@ -1791,7 +1791,10 @@ public class JobInfo implements Parcelable {
* <ol>
* <li>Run as soon as possible</li>
* <li>Be less restricted during Doze and battery saver</li>
- * <li>Bypass Doze, app standby, and battery saver network restrictions</li>
+ * <li>
+ * Bypass Doze, app standby, and battery saver network restrictions (if the job
+ * has a {@link #setRequiredNetwork(NetworkRequest) connectivity constraint})
+ * </li>
* <li>Be less likely to be killed than regular jobs</li>
* <li>Be subject to background location throttling</li>
* <li>Be exempt from delay to optimize job execution</li>
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 23b36e20b174..bff43534ce05 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -3859,10 +3859,16 @@ public class JobSchedulerService extends com.android.server.SystemService
// Only let the app use the higher runtime if it hasn't repeatedly timed out.
final String timeoutTag = job.shouldTreatAsExpeditedJob()
? QUOTA_TRACKER_TIMEOUT_EJ_TAG : QUOTA_TRACKER_TIMEOUT_REG_TAG;
+ // Developers are informed that expedited jobs can be stopped earlier than regular jobs
+ // and so shouldn't use them for long pieces of work. There's little reason to let
+ // them run longer than the normal 10 minutes.
+ final long normalUpperLimitMs = job.shouldTreatAsExpeditedJob()
+ ? mConstants.RUNTIME_MIN_GUARANTEE_MS
+ : mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS;
final long upperLimitMs =
mQuotaTracker.isWithinQuota(job.getTimeoutBlameUserId(),
job.getTimeoutBlamePackageName(), timeoutTag)
- ? mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS
+ ? normalUpperLimitMs
: mConstants.RUNTIME_MIN_GUARANTEE_MS;
return Math.min(upperLimitMs,
mConstants.USE_TARE_POLICY
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
index 2d49cfb3b171..721a8bdce57a 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
@@ -427,34 +427,30 @@ public final class JobServiceContext implements ServiceConnection {
boolean binding = false;
boolean startedWithForegroundFlag = false;
try {
- final Context.BindServiceFlags bindFlags;
+ long bindFlags = Context.BIND_AUTO_CREATE | Context.BIND_NOT_APP_COMPONENT_USAGE;
if (job.shouldTreatAsUserInitiatedJob() && !job.isUserBgRestricted()) {
// If the user has bg restricted the app, don't give the job FG privileges
// such as bypassing data saver or getting the higher foreground proc state.
// If we've gotten to this point, the app is most likely in the foreground,
// so the job will run just fine while the user keeps the app in the foreground.
- bindFlags = Context.BindServiceFlags.of(
- Context.BIND_AUTO_CREATE
- | Context.BIND_ALMOST_PERCEPTIBLE
- | Context.BIND_BYPASS_POWER_NETWORK_RESTRICTIONS
- | Context.BIND_BYPASS_USER_NETWORK_RESTRICTIONS
- | Context.BIND_NOT_APP_COMPONENT_USAGE);
+ bindFlags |= Context.BIND_ALMOST_PERCEPTIBLE;
+ if (job.hasConnectivityConstraint()) {
+ // Only add network restriction bypass flags if the job requires network.
+ bindFlags |= Context.BIND_BYPASS_POWER_NETWORK_RESTRICTIONS
+ | Context.BIND_BYPASS_USER_NETWORK_RESTRICTIONS;
+ }
startedWithForegroundFlag = true;
} else if (job.shouldTreatAsExpeditedJob() || job.shouldTreatAsUserInitiatedJob()) {
- bindFlags = Context.BindServiceFlags.of(
- Context.BIND_AUTO_CREATE
- | Context.BIND_NOT_FOREGROUND
- | Context.BIND_ALMOST_PERCEPTIBLE
- | Context.BIND_BYPASS_POWER_NETWORK_RESTRICTIONS
- | Context.BIND_NOT_APP_COMPONENT_USAGE);
+ bindFlags |= Context.BIND_NOT_FOREGROUND | Context.BIND_ALMOST_PERCEPTIBLE;
+ if (job.hasConnectivityConstraint()) {
+ // Only add network restriction bypass flags if the job requires network.
+ bindFlags |= Context.BIND_BYPASS_POWER_NETWORK_RESTRICTIONS;
+ }
} else {
- bindFlags = Context.BindServiceFlags.of(
- Context.BIND_AUTO_CREATE
- | Context.BIND_NOT_FOREGROUND
- | Context.BIND_NOT_PERCEPTIBLE
- | Context.BIND_NOT_APP_COMPONENT_USAGE);
+ bindFlags |= Context.BIND_NOT_FOREGROUND | Context.BIND_NOT_PERCEPTIBLE;
}
- binding = mContext.bindServiceAsUser(intent, this, bindFlags,
+ binding = mContext.bindServiceAsUser(intent, this,
+ Context.BindServiceFlags.of(bindFlags),
UserHandle.of(job.getUserId()));
} catch (SecurityException e) {
// Some permission policy, for example INTERACT_ACROSS_USERS and
diff --git a/core/api/current.txt b/core/api/current.txt
index 1b0311d19a8d..013010be95be 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -18633,6 +18633,7 @@ package android.hardware.biometrics {
method @Deprecated @Nullable public android.security.identity.IdentityCredential getIdentityCredential();
method @FlaggedApi("android.hardware.biometrics.add_key_agreement_crypto_object") @Nullable public javax.crypto.KeyAgreement getKeyAgreement();
method @Nullable public javax.crypto.Mac getMac();
+ method @FlaggedApi("android.hardware.biometrics.get_op_id_crypto_object") public long getOpId();
method @Nullable public android.security.identity.PresentationSession getPresentationSession();
method @Nullable public java.security.Signature getSignature();
}
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 814be2f8d006..346d62bf8a30 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -4090,7 +4090,7 @@ package android.content.pm {
field public static final int PROTECTION_FLAG_MODULE = 4194304; // 0x400000
field public static final int PROTECTION_FLAG_OEM = 16384; // 0x4000
field public static final int PROTECTION_FLAG_RECENTS = 33554432; // 0x2000000
- field public static final int PROTECTION_FLAG_RETAIL_DEMO = 16777216; // 0x1000000
+ field @Deprecated public static final int PROTECTION_FLAG_RETAIL_DEMO = 16777216; // 0x1000000
field public static final int PROTECTION_FLAG_ROLE = 67108864; // 0x4000000
field public static final int PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER = 65536; // 0x10000
field public static final int PROTECTION_FLAG_VENDOR_PRIVILEGED = 32768; // 0x8000
diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java
index cdda12eebdc4..012b6c49f4c5 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -273,6 +273,9 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable {
* to the <code>retailDemo</code> value of
* {@link android.R.attr#protectionLevel}.
*
+ * @deprecated This flag has been replaced by the retail demo role and is a no-op since Android
+ * V.
+ *
* @hide
*/
@SystemApi
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index 7a43286692c4..97bbfbbe4908 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -21,6 +21,7 @@ import static android.Manifest.permission.USE_BIOMETRIC;
import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
import static android.hardware.biometrics.BiometricManager.Authenticators;
import static android.hardware.biometrics.Flags.FLAG_ADD_KEY_AGREEMENT_CRYPTO_OBJECT;
+import static android.hardware.biometrics.Flags.FLAG_GET_OP_ID_CRYPTO_OBJECT;
import android.annotation.CallbackExecutor;
import android.annotation.FlaggedApi;
@@ -851,6 +852,14 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
public @Nullable KeyAgreement getKeyAgreement() {
return super.getKeyAgreement();
}
+
+ /**
+ * Get the operation handle associated with this object or 0 if none.
+ */
+ @FlaggedApi(FLAG_GET_OP_ID_CRYPTO_OBJECT)
+ public long getOpId() {
+ return super.getOpId();
+ }
}
/**
diff --git a/core/java/android/hardware/biometrics/CryptoObject.java b/core/java/android/hardware/biometrics/CryptoObject.java
index 39fbe83b6abb..8d3ea3f914ec 100644
--- a/core/java/android/hardware/biometrics/CryptoObject.java
+++ b/core/java/android/hardware/biometrics/CryptoObject.java
@@ -154,7 +154,7 @@ public class CryptoObject {
* @hide
* @return the opId associated with this object or 0 if none
*/
- public final long getOpId() {
+ public long getOpId() {
if (mCrypto == null) {
return 0;
} else if (mCrypto instanceof IdentityCredential) {
diff --git a/core/java/android/hardware/biometrics/flags.aconfig b/core/java/android/hardware/biometrics/flags.aconfig
index 979f5705378c..56ec7632fa20 100644
--- a/core/java/android/hardware/biometrics/flags.aconfig
+++ b/core/java/android/hardware/biometrics/flags.aconfig
@@ -14,3 +14,10 @@ flag {
bug: "282058146"
}
+flag {
+ name: "get_op_id_crypto_object"
+ namespace: "biometrics"
+ description: "Feature flag for adding a get operation id api to CryptoObject."
+ bug: "307601768"
+}
+
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 9f931b4059c8..c012ff34bfab 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -15279,6 +15279,7 @@ public final class Settings {
* max_history_files (int)
* max_history_buffer_kb (int)
* battery_charged_delay_ms (int)
+ * battery_charging_enforce_level (int)
* </pre>
*
* <p>
@@ -18306,8 +18307,11 @@ public final class Settings {
/**
* Delay for sending ACTION_CHARGING after device is plugged in.
- * This is used as an override for constants defined in BatteryStatsImpl for
- * ease of experimentation.
+ * This is used as an override for constants defined in BatteryStatsImpl. Its purposes are:
+ * <ol>
+ * <li>Ease of experimentation</li>
+ * <li>Customization of different device</li>
+ * </ol>
*
* @see com.android.internal.os.BatteryStatsImpl.Constants.KEY_BATTERY_CHARGED_DELAY_MS
* @hide
@@ -18317,6 +18321,22 @@ public final class Settings {
"battery_charging_state_update_delay";
/**
+ * Threshold battery level to enforce battery state as charging. That means when battery
+ * level is equal to or higher than this threshold, it is always considered charging, even
+ * if battery level lowered.
+ * This is used as an override for constants defined in BatteryStatsImpl. Its purposes are:
+ * <ol>
+ * <li>Ease of experimentation</li>
+ * <li>Customization of different device</li>
+ * </ol>
+ *
+ * @hide
+ * @see com.android.internal.os.BatteryStatsImpl.Constants.BATTERY_CHARGING_ENFORCE_LEVEL
+ */
+ public static final String BATTERY_CHARGING_STATE_ENFORCE_LEVEL =
+ "battery_charging_state_enforce_level";
+
+ /**
* A serialized string of params that will be loaded into a text classifier action model.
*
* @hide
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 9d88af95ade8..451a71b71e3f 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -2671,7 +2671,7 @@ public final class SurfaceControl implements Parcelable {
*
* @param minAlpha The min alpha the {@link SurfaceControl} is required to
* have to be considered inside the threshold.
- * @param minFractionRendered The min fraction of the SurfaceControl that was resented
+ * @param minFractionRendered The min fraction of the SurfaceControl that was presented
* to the user to be considered inside the threshold.
* @param stabilityRequirementMs The time in milliseconds required for the
* {@link SurfaceControl} to be in the threshold.
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 95f14931c6ef..9f99dc94bc92 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -301,7 +301,9 @@
granted to the system companion device manager service -->
<flag name="companion" value="0x800000" />
<!-- Additional flag from base permission type: this permission will be granted to the
- retail demo app, as defined by the OEM. -->
+ retail demo app, as defined by the OEM.
+ This flag has been replaced by the retail demo role and is a no-op since Android V.
+ -->
<flag name="retailDemo" value="0x1000000" />
<!-- Additional flag from base permission type: this permission will be granted to the
recents app. -->
diff --git a/libs/WindowManager/Shell/tests/flicker/appcompat/AndroidTestTemplate.xml b/libs/WindowManager/Shell/tests/flicker/appcompat/AndroidTestTemplate.xml
index 1df11369a049..5b2ffec67e93 100644
--- a/libs/WindowManager/Shell/tests/flicker/appcompat/AndroidTestTemplate.xml
+++ b/libs/WindowManager/Shell/tests/flicker/appcompat/AndroidTestTemplate.xml
@@ -95,14 +95,6 @@
<option name="pull-pattern-keys" value="perfetto_file_path"/>
<option name="directory-keys"
value="/data/user/0/com.android.wm.shell.flicker/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.wm.shell.flicker.bubbles/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.wm.shell.flicker.pip/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.wm.shell.flicker.splitscreen/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.wm.shell.flicker.service/files"/>
<option name="collect-on-run-ended-only" value="true"/>
<option name="clean-up" value="true"/>
</metrics_collector>
diff --git a/libs/WindowManager/Shell/tests/flicker/bubble/AndroidTestTemplate.xml b/libs/WindowManager/Shell/tests/flicker/bubble/AndroidTestTemplate.xml
index 1df11369a049..9f7d9fcf1326 100644
--- a/libs/WindowManager/Shell/tests/flicker/bubble/AndroidTestTemplate.xml
+++ b/libs/WindowManager/Shell/tests/flicker/bubble/AndroidTestTemplate.xml
@@ -94,15 +94,7 @@
<metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
<option name="pull-pattern-keys" value="perfetto_file_path"/>
<option name="directory-keys"
- value="/data/user/0/com.android.wm.shell.flicker/files"/>
- <option name="directory-keys"
value="/data/user/0/com.android.wm.shell.flicker.bubbles/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.wm.shell.flicker.pip/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.wm.shell.flicker.splitscreen/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.wm.shell.flicker.service/files"/>
<option name="collect-on-run-ended-only" value="true"/>
<option name="clean-up" value="true"/>
</metrics_collector>
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/AndroidTestTemplate.xml b/libs/WindowManager/Shell/tests/flicker/pip/AndroidTestTemplate.xml
index 1df11369a049..882b200da3a2 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/AndroidTestTemplate.xml
+++ b/libs/WindowManager/Shell/tests/flicker/pip/AndroidTestTemplate.xml
@@ -94,15 +94,9 @@
<metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
<option name="pull-pattern-keys" value="perfetto_file_path"/>
<option name="directory-keys"
- value="/data/user/0/com.android.wm.shell.flicker/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.wm.shell.flicker.bubbles/files"/>
- <option name="directory-keys"
value="/data/user/0/com.android.wm.shell.flicker.pip/files"/>
<option name="directory-keys"
- value="/data/user/0/com.android.wm.shell.flicker.splitscreen/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.wm.shell.flicker.service/files"/>
+ value="/data/user/0/com.android.wm.shell.flicker.pip.apps/files"/>
<option name="collect-on-run-ended-only" value="true"/>
<option name="clean-up" value="true"/>
</metrics_collector>
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/csuiteDefaultTemplate.xml b/libs/WindowManager/Shell/tests/flicker/pip/csuiteDefaultTemplate.xml
index ca182fa5a266..6df65391ea61 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/csuiteDefaultTemplate.xml
+++ b/libs/WindowManager/Shell/tests/flicker/pip/csuiteDefaultTemplate.xml
@@ -57,6 +57,17 @@
<option name="test-file-name" value="WMShellFlickerTestsPipAppsCSuite.apk"/>
<option name="test-file-name" value="FlickerTestApp.apk"/>
</target_preparer>
+
+ <!-- Needed for installing apk's from Play Store -->
+ <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+ <option name="aapt-version" value="AAPT2"/>
+ <option name="throw-if-not-found" value="false"/>
+ <option name="install-arg" value="-d"/>
+ <option name="install-arg" value="-g"/>
+ <option name="install-arg" value="-r"/>
+ <option name="test-file-name" value="pstash://com.netflix.mediaclient"/>
+ </target_preparer>
+
<!-- Enable mocking GPS location by the test app -->
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
<option name="run-command"
@@ -94,28 +105,8 @@
<metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
<option name="pull-pattern-keys" value="perfetto_file_path"/>
<option name="directory-keys"
- value="/data/user/0/com.android.wm.shell.flicker/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.wm.shell.flicker.bubbles/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.wm.shell.flicker.pip/files"/>
- <option name="directory-keys"
value="/data/user/0/com.android.wm.shell.flicker.pip.apps/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.wm.shell.flicker.splitscreen/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.wm.shell.flicker.service/files"/>
<option name="collect-on-run-ended-only" value="true"/>
<option name="clean-up" value="true"/>
</metrics_collector>
-
- <!-- Needed for installing apk's from Play Store -->
- <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
- <option name="aapt-version" value="AAPT2"/>
- <option name="throw-if-not-found" value="false"/>
- <option name="install-arg" value="-d"/>
- <option name="install-arg" value="-g"/>
- <option name="install-arg" value="-r"/>
- <option name="test-file-name" value="pstash://com.netflix.mediaclient"/>
- </target_preparer>
</configuration>
diff --git a/libs/WindowManager/Shell/tests/flicker/service/AndroidTestTemplate.xml b/libs/WindowManager/Shell/tests/flicker/service/AndroidTestTemplate.xml
index 1df11369a049..51a55e359acf 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/AndroidTestTemplate.xml
+++ b/libs/WindowManager/Shell/tests/flicker/service/AndroidTestTemplate.xml
@@ -94,14 +94,6 @@
<metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
<option name="pull-pattern-keys" value="perfetto_file_path"/>
<option name="directory-keys"
- value="/data/user/0/com.android.wm.shell.flicker/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.wm.shell.flicker.bubbles/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.wm.shell.flicker.pip/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.wm.shell.flicker.splitscreen/files"/>
- <option name="directory-keys"
value="/data/user/0/com.android.wm.shell.flicker.service/files"/>
<option name="collect-on-run-ended-only" value="true"/>
<option name="clean-up" value="true"/>
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/AndroidTestTemplate.xml b/libs/WindowManager/Shell/tests/flicker/splitscreen/AndroidTestTemplate.xml
index 1df11369a049..fdda5974d1f9 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/AndroidTestTemplate.xml
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/AndroidTestTemplate.xml
@@ -94,15 +94,7 @@
<metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
<option name="pull-pattern-keys" value="perfetto_file_path"/>
<option name="directory-keys"
- value="/data/user/0/com.android.wm.shell.flicker/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.wm.shell.flicker.bubbles/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.wm.shell.flicker.pip/files"/>
- <option name="directory-keys"
value="/data/user/0/com.android.wm.shell.flicker.splitscreen/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.wm.shell.flicker.service/files"/>
<option name="collect-on-run-ended-only" value="true"/>
<option name="clean-up" value="true"/>
</metrics_collector>
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index abd928486607..576ebc1579ef 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -24,6 +24,7 @@
#include <SkColor.h>
#include <android-base/stringprintf.h>
#include <android-base/thread_annotations.h>
+#include <com_android_input_flags.h>
#include <ftl/enum.h>
#include <mutex>
@@ -34,6 +35,8 @@
#define INDENT2 " "
#define INDENT3 " "
+namespace input_flags = com::android::input::flags;
+
namespace android {
namespace {
@@ -63,10 +66,20 @@ void PointerController::DisplayInfoListener::onPointerControllerDestroyed() {
std::shared_ptr<PointerController> PointerController::create(
const sp<PointerControllerPolicyInterface>& policy, const sp<Looper>& looper,
- SpriteController& spriteController, bool enabled) {
+ SpriteController& spriteController, bool enabled, ControllerType type) {
// using 'new' to access non-public constructor
- std::shared_ptr<PointerController> controller = std::shared_ptr<PointerController>(
- new PointerController(policy, looper, spriteController, enabled));
+ std::shared_ptr<PointerController> controller;
+ switch (type) {
+ case ControllerType::MOUSE:
+ controller = std::shared_ptr<PointerController>(
+ new MousePointerController(policy, looper, spriteController, enabled));
+ break;
+ case ControllerType::LEGACY:
+ default:
+ controller = std::shared_ptr<PointerController>(
+ new PointerController(policy, looper, spriteController, enabled));
+ break;
+ }
/*
* Now we need to hook up the constructed PointerController object to its callbacks.
@@ -375,4 +388,13 @@ std::string PointerController::dump() {
return dump;
}
+// --- MousePointerController ---
+
+MousePointerController::MousePointerController(const sp<PointerControllerPolicyInterface>& policy,
+ const sp<Looper>& looper,
+ SpriteController& spriteController, bool enabled)
+ : PointerController(policy, looper, spriteController, enabled) {
+ PointerController::setPresentation(Presentation::POINTER);
+}
+
} // namespace android
diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h
index aa7ca3c52ecf..08e19a096d87 100644
--- a/libs/input/PointerController.h
+++ b/libs/input/PointerController.h
@@ -47,7 +47,8 @@ class PointerController : public PointerControllerInterface {
public:
static std::shared_ptr<PointerController> create(
const sp<PointerControllerPolicyInterface>& policy, const sp<Looper>& looper,
- SpriteController& spriteController, bool enabled);
+ SpriteController& spriteController, bool enabled,
+ ControllerType type = ControllerType::LEGACY);
~PointerController() override;
@@ -75,7 +76,7 @@ public:
void onDisplayInfosChangedLocked(const std::vector<gui::DisplayInfo>& displayInfos)
REQUIRES(getLock());
- std::string dump();
+ std::string dump() override;
protected:
using WindowListenerConsumer =
@@ -87,10 +88,10 @@ protected:
WindowListenerConsumer registerListener,
WindowListenerConsumer unregisterListener);
-private:
PointerController(const sp<PointerControllerPolicyInterface>& policy, const sp<Looper>& looper,
SpriteController& spriteController, bool enabled);
+private:
friend PointerControllerContext::LooperCallback;
friend PointerControllerContext::MessageHandler;
@@ -135,6 +136,24 @@ private:
void clearSpotsLocked() REQUIRES(getLock());
};
+class MousePointerController : public PointerController {
+public:
+ /** A version of PointerController that controls one mouse pointer. */
+ MousePointerController(const sp<PointerControllerPolicyInterface>& policy,
+ const sp<Looper>& looper, SpriteController& spriteController,
+ bool enabled);
+
+ void setPresentation(Presentation) override {
+ LOG_ALWAYS_FATAL("Should not be called");
+ }
+ void setSpots(const PointerCoords*, const uint32_t*, BitSet32, int32_t) override {
+ LOG_ALWAYS_FATAL("Should not be called");
+ }
+ void clearSpots() override {
+ LOG_ALWAYS_FATAL("Should not be called");
+ }
+};
+
} // namespace android
#endif // _UI_POINTER_CONTROLLER_H
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 4c9436b4e151..89a8dd95d3c3 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -327,4 +327,12 @@
<!-- Whether wifi is always requested by default. -->
<bool name="def_enable_wifi_always_requested">false</bool>
+
+ <!-- Default for Settings.BATTERY_CHARGING_STATE_UPDATE_DELAY in millisecond.
+ -1 means system internal default value is used. -->
+ <integer name="def_battery_charging_state_update_delay_ms">-1</integer>
+
+ <!-- Default for Settings.BATTERY_CHARGING_STATE_ENFORCE_LEVEL.
+ -1 means system internal default value is used. -->
+ <integer name="def_battery_charging_state_enforce_level">-1</integer>
</resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 785003a355fc..b0abf92ffe08 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -3792,7 +3792,7 @@ public class SettingsProvider extends ContentProvider {
}
private final class UpgradeController {
- private static final int SETTINGS_VERSION = 223;
+ private static final int SETTINGS_VERSION = 224;
private final int mUserId;
@@ -5965,8 +5965,23 @@ public class SettingsProvider extends ContentProvider {
// Do nothing. Leave the value as is.
}
}
+ }
+
+ currentVersion = 223;
- currentVersion = 223;
+ // Version 223: make charging constraint update criteria customizable.
+ if (currentVersion == 223) {
+ initGlobalSettingsDefaultValLocked(
+ Global.BATTERY_CHARGING_STATE_UPDATE_DELAY,
+ getContext().getResources().getInteger(
+ R.integer.def_battery_charging_state_update_delay_ms));
+
+ initGlobalSettingsDefaultValLocked(
+ Global.BATTERY_CHARGING_STATE_ENFORCE_LEVEL,
+ getContext().getResources().getInteger(
+ R.integer.def_battery_charging_state_enforce_level)
+ );
+ currentVersion = 224;
}
// vXXX: Add new settings above this point.
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 1f171ba48343..2e174e267bde 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -145,6 +145,7 @@ public class SettingsBackupTest {
Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS,
Settings.Global.AUTO_TIME_ZONE_EXPLICIT,
Settings.Global.AVERAGE_TIME_TO_DISCHARGE,
+ Settings.Global.BATTERY_CHARGING_STATE_ENFORCE_LEVEL,
Settings.Global.BATTERY_CHARGING_STATE_UPDATE_DELAY,
Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME,
Settings.Global.BROADCAST_BG_CONSTANTS,
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index a9027deccfda..069ba6cd02aa 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -53,6 +53,14 @@ flag {
}
flag {
+ name: "keyguard_bottom_area_refactor"
+ namespace: "systemui"
+ description: "Bottom area of keyguard refactor move into KeyguardRootView. Includes "
+ "lock icon and others."
+ bug: "290652751"
+}
+
+flag {
name: "visual_interruptions_refactor"
namespace: "systemui"
description: "Enables the refactored version of the code to decide when notifications "
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
index f2b7b3290f96..56970d7e3005 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
@@ -19,6 +19,7 @@ package com.android.systemui.bouncer.ui.composable
import android.app.AlertDialog
import android.app.Dialog
import android.content.DialogInterface
+import android.content.res.Configuration
import androidx.compose.animation.Crossfade
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.snap
@@ -50,6 +51,7 @@ import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
+import androidx.compose.material3.windowsizeclass.WindowHeightSizeClass
import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
@@ -63,6 +65,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.pointerInput
+import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.res.stringResource
@@ -136,7 +139,7 @@ private fun SceneScope.BouncerScene(
modifier: Modifier = Modifier,
) {
val backgroundColor = MaterialTheme.colorScheme.surface
- val windowSizeClass = LocalWindowSizeClass.current
+ val layout = calculateLayout()
Box(modifier) {
Canvas(Modifier.element(Bouncer.Elements.Background).fillMaxSize()) {
@@ -146,22 +149,30 @@ private fun SceneScope.BouncerScene(
val childModifier = Modifier.element(Bouncer.Elements.Content).fillMaxSize()
val isFullScreenUserSwitcherEnabled = viewModel.isUserSwitcherVisible
- when {
- windowSizeClass.widthSizeClass == WindowWidthSizeClass.Expanded ->
+ when (layout) {
+ Layout.STANDARD ->
+ Bouncer(
+ viewModel = viewModel,
+ dialogFactory = dialogFactory,
+ isUserInputAreaVisible = true,
+ modifier = childModifier,
+ )
+ Layout.SIDE_BY_SIDE ->
SideBySide(
viewModel = viewModel,
dialogFactory = dialogFactory,
+ isUserSwitcherVisible = isFullScreenUserSwitcherEnabled,
modifier = childModifier,
)
- isFullScreenUserSwitcherEnabled &&
- windowSizeClass.widthSizeClass == WindowWidthSizeClass.Medium ->
+ Layout.STACKED ->
Stacked(
viewModel = viewModel,
dialogFactory = dialogFactory,
+ isUserSwitcherVisible = isFullScreenUserSwitcherEnabled,
modifier = childModifier,
)
- else ->
- Bouncer(
+ Layout.SPLIT ->
+ Split(
viewModel = viewModel,
dialogFactory = dialogFactory,
modifier = childModifier,
@@ -178,11 +189,10 @@ private fun SceneScope.BouncerScene(
private fun Bouncer(
viewModel: BouncerViewModel,
dialogFactory: BouncerSceneDialogFactory,
+ isUserInputAreaVisible: Boolean,
modifier: Modifier = Modifier,
) {
val message: BouncerViewModel.MessageViewModel by viewModel.message.collectAsState()
- val authMethodViewModel: AuthMethodBouncerViewModel? by
- viewModel.authMethodViewModel.collectAsState()
val dialogMessage: String? by viewModel.throttlingDialogMessage.collectAsState()
var dialog: Dialog? by remember { mutableStateOf(null) }
@@ -204,25 +214,11 @@ private fun Bouncer(
}
Box(Modifier.weight(1f)) {
- when (val nonNullViewModel = authMethodViewModel) {
- is PinBouncerViewModel ->
- PinBouncer(
- viewModel = nonNullViewModel,
- modifier = Modifier.align(Alignment.Center),
- )
- is PasswordBouncerViewModel ->
- PasswordBouncer(
- viewModel = nonNullViewModel,
- modifier = Modifier.align(Alignment.Center),
- )
- is PatternBouncerViewModel ->
- PatternBouncer(
- viewModel = nonNullViewModel,
- modifier =
- Modifier.aspectRatio(1f, matchHeightConstraintsFirst = false)
- .align(Alignment.BottomCenter),
- )
- else -> Unit
+ if (isUserInputAreaVisible) {
+ UserInputArea(
+ viewModel = viewModel,
+ modifier = Modifier.align(Alignment.Center),
+ )
}
}
@@ -265,6 +261,40 @@ private fun Bouncer(
}
}
+/**
+ * Renders the user input area, where the user interacts with the UI to enter their credentials.
+ *
+ * For example, this can be the pattern input area, the password text box, or pin pad.
+ */
+@Composable
+private fun UserInputArea(
+ viewModel: BouncerViewModel,
+ modifier: Modifier = Modifier,
+) {
+ val authMethodViewModel: AuthMethodBouncerViewModel? by
+ viewModel.authMethodViewModel.collectAsState()
+
+ when (val nonNullViewModel = authMethodViewModel) {
+ is PinBouncerViewModel ->
+ PinBouncer(
+ viewModel = nonNullViewModel,
+ modifier = modifier,
+ )
+ is PasswordBouncerViewModel ->
+ PasswordBouncer(
+ viewModel = nonNullViewModel,
+ modifier = modifier,
+ )
+ is PatternBouncerViewModel ->
+ PatternBouncer(
+ viewModel = nonNullViewModel,
+ modifier =
+ Modifier.aspectRatio(1f, matchHeightConstraintsFirst = false).then(modifier)
+ )
+ else -> Unit
+ }
+}
+
/** Renders the UI of the user switcher that's displayed on large screens next to the bouncer UI. */
@Composable
private fun UserSwitcher(
@@ -287,62 +317,57 @@ private fun UserSwitcher(
)
}
- UserSwitcherDropdown(
- items = dropdownItems,
- )
- }
-}
-
-@Composable
-private fun UserSwitcherDropdown(
- items: List<BouncerViewModel.UserSwitcherDropdownItemViewModel>,
-) {
- val (isDropdownExpanded, setDropdownExpanded) = remember { mutableStateOf(false) }
-
- items.firstOrNull()?.let { firstDropdownItem ->
- Spacer(modifier = Modifier.height(40.dp))
+ val (isDropdownExpanded, setDropdownExpanded) = remember { mutableStateOf(false) }
+
+ dropdownItems.firstOrNull()?.let { firstDropdownItem ->
+ Spacer(modifier = Modifier.height(40.dp))
+
+ Box {
+ PlatformButton(
+ modifier =
+ Modifier
+ // Remove the built-in padding applied inside PlatformButton:
+ .padding(vertical = 0.dp)
+ .width(UserSwitcherDropdownWidth)
+ .height(UserSwitcherDropdownHeight),
+ colors =
+ ButtonDefaults.buttonColors(
+ containerColor = MaterialTheme.colorScheme.surfaceContainerHighest,
+ contentColor = MaterialTheme.colorScheme.onSurface,
+ ),
+ onClick = { setDropdownExpanded(!isDropdownExpanded) },
+ ) {
+ val context = LocalContext.current
+ Text(
+ text = checkNotNull(firstDropdownItem.text.loadText(context)),
+ style = MaterialTheme.typography.headlineSmall,
+ maxLines = 1,
+ overflow = TextOverflow.Ellipsis,
+ )
- Box {
- PlatformButton(
- modifier =
- Modifier
- // Remove the built-in padding applied inside PlatformButton:
- .padding(vertical = 0.dp)
- .width(UserSwitcherDropdownWidth)
- .height(UserSwitcherDropdownHeight),
- colors =
- ButtonDefaults.buttonColors(
- containerColor = MaterialTheme.colorScheme.surfaceContainerHighest,
- contentColor = MaterialTheme.colorScheme.onSurface,
- ),
- onClick = { setDropdownExpanded(!isDropdownExpanded) },
- ) {
- val context = LocalContext.current
- Text(
- text = checkNotNull(firstDropdownItem.text.loadText(context)),
- style = MaterialTheme.typography.headlineSmall,
- maxLines = 1,
- overflow = TextOverflow.Ellipsis,
- )
+ Spacer(modifier = Modifier.weight(1f))
- Spacer(modifier = Modifier.weight(1f))
+ Icon(
+ imageVector = Icons.Default.KeyboardArrowDown,
+ contentDescription = null,
+ modifier = Modifier.size(32.dp),
+ )
+ }
- Icon(
- imageVector = Icons.Default.KeyboardArrowDown,
- contentDescription = null,
- modifier = Modifier.size(32.dp),
+ UserSwitcherDropdownMenu(
+ isExpanded = isDropdownExpanded,
+ items = dropdownItems,
+ onDismissed = { setDropdownExpanded(false) },
)
}
-
- UserSwitcherDropdownMenu(
- isExpanded = isDropdownExpanded,
- items = items,
- onDismissed = { setDropdownExpanded(false) },
- )
}
}
}
+/**
+ * Renders the dropdowm menu that displays the actual users and/or user actions that can be
+ * selected.
+ */
@Composable
private fun UserSwitcherDropdownMenu(
isExpanded: Boolean,
@@ -396,19 +421,47 @@ private fun UserSwitcherDropdownMenu(
}
/**
- * Arranges the bouncer contents and user switcher contents side-by-side, supporting a double tap
- * anywhere on the background to flip their positions.
+ * Renders the bouncer UI in split mode, with half on one side and half on the other side, swappable
+ * by double-tapping on the side.
*/
@Composable
-private fun SideBySide(
+private fun Split(
viewModel: BouncerViewModel,
dialogFactory: BouncerSceneDialogFactory,
modifier: Modifier = Modifier,
) {
+ SwappableLayout(
+ startContent = { startContentModifier ->
+ Bouncer(
+ viewModel = viewModel,
+ dialogFactory = dialogFactory,
+ isUserInputAreaVisible = false,
+ modifier = startContentModifier,
+ )
+ },
+ endContent = { endContentModifier ->
+ UserInputArea(
+ viewModel = viewModel,
+ modifier = endContentModifier,
+ )
+ },
+ modifier = modifier
+ )
+}
+
+/**
+ * Arranges the given two contents side-by-side, supporting a double tap anywhere on the background
+ * to flip their positions.
+ */
+@Composable
+private fun SwappableLayout(
+ startContent: @Composable (Modifier) -> Unit,
+ endContent: @Composable (Modifier) -> Unit,
+ modifier: Modifier = Modifier,
+) {
val layoutDirection = LocalLayoutDirection.current
val isLeftToRight = layoutDirection == LayoutDirection.Ltr
- val (isUserSwitcherFirst, setUserSwitcherFirst) =
- rememberSaveable(isLeftToRight) { mutableStateOf(isLeftToRight) }
+ val (isSwapped, setSwapped) = rememberSaveable(isLeftToRight) { mutableStateOf(!isLeftToRight) }
Row(
modifier =
@@ -416,9 +469,8 @@ private fun SideBySide(
detectTapGestures(
onDoubleTap = { offset ->
// Depending on where the user double tapped, switch the elements such that
- // the bouncer contents element is closer to the side that was double
- // tapped.
- setUserSwitcherFirst(offset.x > size.width / 2)
+ // the endContent is closer to the side that was double tapped.
+ setSwapped(offset.x < size.width / 2)
}
)
},
@@ -426,39 +478,30 @@ private fun SideBySide(
val animatedOffset by
animateFloatAsState(
targetValue =
- if (isUserSwitcherFirst) {
- // When the user switcher is first, both elements have their natural
- // placement so they are not offset in any way.
+ if (!isSwapped) {
+ // When startContent is first, both elements have their natural placement so
+ // they are not offset in any way.
0f
} else if (isLeftToRight) {
- // Since the user switcher is not first, the elements have to be swapped
- // horizontally. In the case of LTR locales, this means pushing the user
- // switcher to the right, hence the positive number.
+ // Since startContent is not first, the elements have to be swapped
+ // horizontally. In the case of LTR locales, this means pushing startContent
+ // to the right, hence the positive number.
1f
} else {
- // Since the user switcher is not first, the elements have to be swapped
- // horizontally. In the case of RTL locale, this means pushing the user
- // switcher to the left, hence the negative number.
+ // Since startContent is not first, the elements have to be swapped
+ // horizontally. In the case of RTL locales, this means pushing startContent
+ // to the left, hence the negative number.
-1f
},
label = "offset",
)
- val userSwitcherModifier =
+ startContent(
Modifier.fillMaxHeight().weight(1f).graphicsLayer {
translationX = size.width * animatedOffset
alpha = animatedAlpha(animatedOffset)
}
- if (viewModel.isUserSwitcherVisible) {
- UserSwitcher(
- viewModel = viewModel,
- modifier = userSwitcherModifier,
- )
- } else {
- Box(
- modifier = userSwitcherModifier,
- )
- }
+ )
Box(
modifier =
@@ -469,41 +512,124 @@ private fun SideBySide(
alpha = animatedAlpha(animatedOffset)
}
) {
+ endContent(Modifier.widthIn(max = 400.dp).align(Alignment.BottomCenter))
+ }
+ }
+}
+
+/**
+ * Arranges the bouncer contents and user switcher contents side-by-side, supporting a double tap
+ * anywhere on the background to flip their positions.
+ */
+@Composable
+private fun SideBySide(
+ viewModel: BouncerViewModel,
+ dialogFactory: BouncerSceneDialogFactory,
+ isUserSwitcherVisible: Boolean,
+ modifier: Modifier = Modifier,
+) {
+ SwappableLayout(
+ startContent = { startContentModifier ->
+ if (isUserSwitcherVisible) {
+ UserSwitcher(
+ viewModel = viewModel,
+ modifier = startContentModifier,
+ )
+ } else {
+ Box(
+ modifier = startContentModifier,
+ )
+ }
+ },
+ endContent = { endContentModifier ->
Bouncer(
viewModel = viewModel,
dialogFactory = dialogFactory,
- modifier = Modifier.widthIn(max = 400.dp).align(Alignment.BottomCenter),
+ isUserInputAreaVisible = true,
+ modifier = endContentModifier,
)
- }
- }
+ },
+ modifier = modifier,
+ )
}
-/** Arranges the bouncer contents and user switcher contents one on top of the other. */
+/** Arranges the bouncer contents and user switcher contents one on top of the other, vertically. */
@Composable
private fun Stacked(
viewModel: BouncerViewModel,
dialogFactory: BouncerSceneDialogFactory,
+ isUserSwitcherVisible: Boolean,
modifier: Modifier = Modifier,
) {
Column(
modifier = modifier,
) {
- UserSwitcher(
- viewModel = viewModel,
- modifier = Modifier.fillMaxWidth().weight(1f),
- )
+ if (isUserSwitcherVisible) {
+ UserSwitcher(
+ viewModel = viewModel,
+ modifier = Modifier.fillMaxWidth().weight(1f),
+ )
+ }
+
Bouncer(
viewModel = viewModel,
dialogFactory = dialogFactory,
+ isUserInputAreaVisible = true,
modifier = Modifier.fillMaxWidth().weight(1f),
)
}
}
+@Composable
+private fun calculateLayout(): Layout {
+ val windowSizeClass = LocalWindowSizeClass.current
+ val width = windowSizeClass.widthSizeClass
+ val height = windowSizeClass.heightSizeClass
+ val isLarge = width > WindowWidthSizeClass.Compact && height > WindowHeightSizeClass.Compact
+ val isTall =
+ when (height) {
+ WindowHeightSizeClass.Expanded -> width < WindowWidthSizeClass.Expanded
+ WindowHeightSizeClass.Medium -> width < WindowWidthSizeClass.Medium
+ else -> false
+ }
+ val isSquare =
+ when (width) {
+ WindowWidthSizeClass.Compact -> height == WindowHeightSizeClass.Compact
+ WindowWidthSizeClass.Medium -> height == WindowHeightSizeClass.Medium
+ WindowWidthSizeClass.Expanded -> height == WindowHeightSizeClass.Expanded
+ else -> false
+ }
+ val isLandscape = LocalConfiguration.current.orientation == Configuration.ORIENTATION_LANDSCAPE
+
+ return when {
+ // Small and tall devices (i.e. phone/folded in portrait) or square device not in landscape
+ // mode (unfolded with hinge along horizontal plane).
+ (!isLarge && isTall) || (isSquare && !isLandscape) -> Layout.STANDARD
+ // Small and wide devices (i.e. phone/folded in landscape).
+ !isLarge -> Layout.SPLIT
+ // Large and tall devices (i.e. tablet in portrait).
+ isTall -> Layout.STACKED
+ // Large and wide/square devices (i.e. tablet in landscape, unfolded).
+ else -> Layout.SIDE_BY_SIDE
+ }
+}
+
interface BouncerSceneDialogFactory {
operator fun invoke(): AlertDialog
}
+/** Enumerates all known adaptive layout configurations. */
+private enum class Layout {
+ /** The default UI with the bouncer laid out normally. */
+ STANDARD,
+ /** The bouncer is displayed vertically stacked with the user switcher. */
+ STACKED,
+ /** The bouncer is displayed side-by-side with the user switcher or an empty space. */
+ SIDE_BY_SIDE,
+ /** The bouncer is split in two with both sides shown side-by-side. */
+ SPLIT,
+}
+
/**
* Calculates an alpha for the user switcher and bouncer such that it's at `1` when the offset of
* the two reaches a stopping point but `0` in the middle of the transition.
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
index 2e93a09deb30..0da562bcb3bb 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
@@ -161,7 +161,8 @@ private fun SceneTransitionObservableTransitionState.toModel(): ObservableTransi
fromScene = fromScene.toModel().key,
toScene = toScene.toModel().key,
progress = progress,
- isUserInputDriven = isUserInputDriven,
+ isInitiatedByUserInput = isInitiatedByUserInput,
+ isUserInputOngoing = isUserInputOngoing,
)
}
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt
index 88944f10eab9..199832bc4ab6 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt
@@ -108,7 +108,7 @@ private fun CoroutineScope.animate(
) {
val fromScene = layoutImpl.state.transitionState.currentScene
val isUserInput =
- (layoutImpl.state.transitionState as? TransitionState.Transition)?.isUserInputDriven
+ (layoutImpl.state.transitionState as? TransitionState.Transition)?.isInitiatedByUserInput
?: false
val animationSpec = layoutImpl.transitions.transitionSpec(fromScene, target).spec
@@ -119,9 +119,23 @@ private fun CoroutineScope.animate(
val targetProgress = if (reversed) 0f else 1f
val transition =
if (reversed) {
- OneOffTransition(target, fromScene, currentScene = target, isUserInput, animatable)
+ OneOffTransition(
+ fromScene = target,
+ toScene = fromScene,
+ currentScene = target,
+ isInitiatedByUserInput = isUserInput,
+ isUserInputOngoing = false,
+ animatable = animatable,
+ )
} else {
- OneOffTransition(fromScene, target, currentScene = target, isUserInput, animatable)
+ OneOffTransition(
+ fromScene = fromScene,
+ toScene = target,
+ currentScene = target,
+ isInitiatedByUserInput = isUserInput,
+ isUserInputOngoing = false,
+ animatable = animatable,
+ )
}
// Change the current layout state to use this new transition.
@@ -142,7 +156,8 @@ private class OneOffTransition(
override val fromScene: SceneKey,
override val toScene: SceneKey,
override val currentScene: SceneKey,
- override val isUserInputDriven: Boolean,
+ override val isInitiatedByUserInput: Boolean,
+ override val isUserInputOngoing: Boolean,
private val animatable: Animatable<Float, AnimationVector1D>,
) : TransitionState.Transition {
override val progress: Float
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt
index ccdec6ea8c5e..1b79dbdee510 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt
@@ -52,7 +52,14 @@ sealed class ObservableTransitionState {
* scene, this value will remain true after the pointer is no longer touching the screen and
* will be true in any transition created to animate back to the original position.
*/
- val isUserInputDriven: Boolean,
+ val isInitiatedByUserInput: Boolean,
+
+ /**
+ * Whether user input is currently driving the transition. For example, if a user is
+ * dragging a pointer, this emits true. Once they lift their finger, this emits false while
+ * the transition completes/settles.
+ */
+ val isUserInputOngoing: Flow<Boolean>,
) : ObservableTransitionState()
}
@@ -73,7 +80,8 @@ fun SceneTransitionLayoutState.observableTransitionState(): Flow<ObservableTrans
fromScene = state.fromScene,
toScene = state.toScene,
progress = snapshotFlow { state.progress },
- isUserInputDriven = state.isUserInputDriven,
+ isInitiatedByUserInput = state.isInitiatedByUserInput,
+ isUserInputOngoing = snapshotFlow { state.isUserInputOngoing },
)
}
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
index 7a21211c3dde..b9f83c545122 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
@@ -70,6 +70,9 @@ sealed interface TransitionState {
val progress: Float
/** Whether the transition was triggered by user input rather than being programmatic. */
- val isUserInputDriven: Boolean
+ val isInitiatedByUserInput: Boolean
+
+ /** Whether user input is currently driving the transition. */
+ val isUserInputOngoing: Boolean
}
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
index 8b79c282af9a..877ac095af4e 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
@@ -508,7 +508,7 @@ class SceneGestureHandler(
return offset / distance
}
- override val isUserInputDriven = true
+ override val isInitiatedByUserInput = true
/** The current offset caused by the drag gesture. */
var dragOffset by mutableFloatStateOf(0f)
@@ -519,6 +519,10 @@ class SceneGestureHandler(
*/
var isAnimatingOffset by mutableStateOf(false)
+ // If we are not animating offset, it means the offset is being driven by the user's finger.
+ override val isUserInputOngoing: Boolean
+ get() = !isAnimatingOffset
+
/** The animatable used to animate the offset once the user lifted its finger. */
val offsetAnimatable = Animatable(0f, OffsetVisibilityThreshold)
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
index 4a6066f5c664..58d853ef5a00 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
@@ -136,7 +136,7 @@ class SwipeToSceneTest {
assertThat(transition.toScene).isEqualTo(TestScenes.SceneB)
assertThat(transition.currentScene).isEqualTo(TestScenes.SceneA)
assertThat(transition.progress).isEqualTo(55.dp / LayoutWidth)
- assertThat(transition.isUserInputDriven).isTrue()
+ assertThat(transition.isInitiatedByUserInput).isTrue()
// Release the finger. We should now be animating back to A (currentScene = SceneA) given
// that 55dp < positional threshold.
@@ -148,7 +148,7 @@ class SwipeToSceneTest {
assertThat(transition.toScene).isEqualTo(TestScenes.SceneB)
assertThat(transition.currentScene).isEqualTo(TestScenes.SceneA)
assertThat(transition.progress).isEqualTo(55.dp / LayoutWidth)
- assertThat(transition.isUserInputDriven).isTrue()
+ assertThat(transition.isInitiatedByUserInput).isTrue()
// Wait for the animation to finish. We should now be in scene A.
rule.waitForIdle()
@@ -170,7 +170,7 @@ class SwipeToSceneTest {
assertThat(transition.toScene).isEqualTo(TestScenes.SceneC)
assertThat(transition.currentScene).isEqualTo(TestScenes.SceneA)
assertThat(transition.progress).isEqualTo(56.dp / LayoutHeight)
- assertThat(transition.isUserInputDriven).isTrue()
+ assertThat(transition.isInitiatedByUserInput).isTrue()
// Release the finger. We should now be animating to C (currentScene = SceneC) given
// that 56dp >= positional threshold.
@@ -182,7 +182,7 @@ class SwipeToSceneTest {
assertThat(transition.toScene).isEqualTo(TestScenes.SceneC)
assertThat(transition.currentScene).isEqualTo(TestScenes.SceneC)
assertThat(transition.progress).isEqualTo(56.dp / LayoutHeight)
- assertThat(transition.isUserInputDriven).isTrue()
+ assertThat(transition.isInitiatedByUserInput).isTrue()
// Wait for the animation to finish. We should now be in scene C.
rule.waitForIdle()
diff --git a/packages/SystemUI/src/com/android/systemui/aconfig/AConfigModule.kt b/packages/SystemUI/src/com/android/systemui/aconfig/AConfigModule.kt
deleted file mode 100644
index fa61bba6922d..000000000000
--- a/packages/SystemUI/src/com/android/systemui/aconfig/AConfigModule.kt
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.aconfig
-
-import com.android.systemui.FeatureFlags
-import com.android.systemui.FeatureFlagsImpl
-import com.android.systemui.dagger.SysUISingleton
-import dagger.Module
-import dagger.Provides
-
-@Module
-abstract class AConfigModule {
- @Module
- companion object {
- @Provides
- @SysUISingleton
- fun providesImpl(): FeatureFlags {
- return FeatureFlagsImpl()
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index e69eced0de45..1ac4163649a4 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -489,6 +489,10 @@ public class AuthContainerView extends LinearLayout
public void onAttachedToWindow() {
super.onAttachedToWindow();
+ if (mContainerState == STATE_ANIMATING_OUT) {
+ return;
+ }
+
mWakefulnessLifecycle.addObserver(this);
mPanelInteractionDetector.enable(
() -> animateAway(AuthDialogCallback.DISMISSED_USER_CANCELED));
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt
index 2bb19cdadc29..f51379940640 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt
@@ -26,8 +26,6 @@ import com.android.systemui.biometrics.shared.model.DisplayRotation
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
import com.android.systemui.biometrics.shared.model.isDefaultOrientation
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.flags.FeatureFlagsClassic
-import com.android.systemui.flags.Flags
import com.android.systemui.log.SideFpsLogger
import com.android.systemui.res.R
import java.util.Optional
@@ -48,7 +46,6 @@ constructor(
fingerprintPropertyRepository: FingerprintPropertyRepository,
windowManager: WindowManager,
displayStateInteractor: DisplayStateInteractor,
- featureFlags: FeatureFlagsClassic,
fingerprintInteractiveToAuthProvider: Optional<FingerprintInteractiveToAuthProvider>,
private val logger: SideFpsLogger,
) {
@@ -65,14 +62,11 @@ constructor(
val isAvailable: Flow<Boolean> =
fingerprintPropertyRepository.sensorType.map { it == FingerprintSensorType.POWER_BUTTON }
- val authenticationDuration: Flow<Long> =
- flowOf(context.resources?.getInteger(R.integer.config_restToUnlockDuration)?.toLong() ?: 0L)
+ val authenticationDuration: Long =
+ context.resources?.getInteger(R.integer.config_restToUnlockDuration)?.toLong() ?: 0L
val isProlongedTouchRequiredForAuthentication: Flow<Boolean> =
- if (
- fingerprintInteractiveToAuthProvider.isEmpty ||
- !featureFlags.isEnabled(Flags.REST_TO_UNLOCK)
- ) {
+ if (fingerprintInteractiveToAuthProvider.isEmpty) {
flowOf(false)
} else {
combine(
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalRepository.kt
index 9cab17e9f6c4..5c4ee3524a44 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalRepository.kt
@@ -1,6 +1,6 @@
package com.android.systemui.communal.data.repository
-import com.android.systemui.FeatureFlags
+import com.android.systemui.Flags.communalHub
import com.android.systemui.communal.shared.model.CommunalSceneKey
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FeatureFlagsClassic
@@ -29,13 +29,10 @@ interface CommunalRepository {
class CommunalRepositoryImpl
@Inject
constructor(
- private val featureFlags: FeatureFlags,
private val featureFlagsClassic: FeatureFlagsClassic,
) : CommunalRepository {
override val isCommunalEnabled: Boolean
- get() =
- featureFlagsClassic.isEnabled(Flags.COMMUNAL_SERVICE_ENABLED) &&
- featureFlags.communalHub()
+ get() = featureFlagsClassic.isEnabled(Flags.COMMUNAL_SERVICE_ENABLED) && communalHub()
private val _desiredScene: MutableStateFlow<CommunalSceneKey> =
MutableStateFlow(CommunalSceneKey.Blank)
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 7915088b4642..f3353c7f26dc 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -29,7 +29,6 @@ import com.android.systemui.BootCompleteCache;
import com.android.systemui.BootCompleteCacheImpl;
import com.android.systemui.accessibility.AccessibilityModule;
import com.android.systemui.accessibility.data.repository.AccessibilityRepositoryModule;
-import com.android.systemui.aconfig.AConfigModule;
import com.android.systemui.appops.dagger.AppOpsModule;
import com.android.systemui.assist.AssistModule;
import com.android.systemui.authentication.AuthenticationModule;
@@ -163,7 +162,6 @@ import javax.inject.Named;
@Module(includes = {
AccessibilityModule.class,
AccessibilityRepositoryModule.class,
- AConfigModule.class,
AppOpsModule.class,
AssistModule.class,
AuthenticationModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsClassicDebug.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsClassicDebug.java
index 36d789ec049b..87c12b4a5a59 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsClassicDebug.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsClassicDebug.java
@@ -17,6 +17,7 @@
package com.android.systemui.flags;
import static com.android.systemui.Flags.exampleFlag;
+import static com.android.systemui.Flags.sysuiTeamfood;
import static com.android.systemui.flags.FlagManager.ACTION_GET_FLAGS;
import static com.android.systemui.flags.FlagManager.ACTION_SET_FLAG;
import static com.android.systemui.flags.FlagManager.EXTRA_FLAGS;
@@ -38,13 +39,10 @@ import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.systemui.FeatureFlags;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.util.settings.GlobalSettings;
-import org.jetbrains.annotations.NotNull;
-
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Map;
@@ -83,7 +81,6 @@ public class FeatureFlagsClassicDebug implements FeatureFlagsClassic {
private final Map<String, Boolean> mBooleanFlagCache = new ConcurrentHashMap<>();
private final Map<String, String> mStringFlagCache = new ConcurrentHashMap<>();
private final Map<String, Integer> mIntFlagCache = new ConcurrentHashMap<>();
- private final FeatureFlags mGantryFlags;
private final Restarter mRestarter;
private final ServerFlagReader.ChangeListener mOnPropertiesChanged =
@@ -128,7 +125,6 @@ public class FeatureFlagsClassicDebug implements FeatureFlagsClassic {
@Main Resources resources,
ServerFlagReader serverFlagReader,
@Named(ALL_FLAGS) Map<String, Flag<?>> allFlags,
- FeatureFlags gantryFlags,
Restarter restarter) {
mFlagManager = flagManager;
mContext = context;
@@ -137,7 +133,6 @@ public class FeatureFlagsClassicDebug implements FeatureFlagsClassic {
mSystemProperties = systemProperties;
mServerFlagReader = serverFlagReader;
mAllFlags = allFlags;
- mGantryFlags = gantryFlags;
mRestarter = restarter;
}
@@ -155,16 +150,16 @@ public class FeatureFlagsClassicDebug implements FeatureFlagsClassic {
}
@Override
- public boolean isEnabled(@NotNull UnreleasedFlag flag) {
+ public boolean isEnabled(@NonNull UnreleasedFlag flag) {
return isEnabledInternal(flag);
}
@Override
- public boolean isEnabled(@NotNull ReleasedFlag flag) {
+ public boolean isEnabled(@NonNull ReleasedFlag flag) {
return isEnabledInternal(flag);
}
- private boolean isEnabledInternal(@NotNull BooleanFlag flag) {
+ private boolean isEnabledInternal(@NonNull BooleanFlag flag) {
String name = flag.getName();
Boolean value = mBooleanFlagCache.get(name);
@@ -266,7 +261,7 @@ public class FeatureFlagsClassicDebug implements FeatureFlagsClassic {
&& !defaultValue
&& result == null
&& flag.getTeamfood()) {
- return mGantryFlags.sysuiTeamfood();
+ return sysuiTeamfood();
}
return result == null ? mServerFlagReader.readServerOverride(
@@ -539,7 +534,7 @@ public class FeatureFlagsClassicDebug implements FeatureFlagsClassic {
@Override
public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
pw.println("can override: true");
- pw.println("teamfood: " + mGantryFlags.sysuiTeamfood());
+ pw.println("teamfood: " + sysuiTeamfood());
pw.println("booleans: " + mBooleanFlagCache.size());
pw.println("example_flag: " + exampleFlag());
pw.println("example_shared_flag: " + exampleSharedFlag());
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index c1106b342cac..49b8ee632d7e 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -296,11 +296,6 @@ object Flags {
@JvmField val MIGRATE_CLOCKS_TO_BLUEPRINT =
unreleasedFlag("migrate_clocks_to_blueprint")
- /** Migrate KeyguardRootView to use composables. */
- // TODO(b/301969856): Tracking Bug.
- @JvmField val KEYGUARD_ROOT_VIEW_USE_COMPOSE =
- unreleasedFlag("keyguard_root_view_use_compose")
-
/** Enables preview loading animation in the wallpaper picker. */
// TODO(b/274443705): Tracking Bug
@JvmField
@@ -532,10 +527,9 @@ object Flags {
@Keep
@JvmField
val WM_ENABLE_PARTIAL_SCREEN_SHARING_ENTERPRISE_POLICIES =
- unreleasedFlag(
- name = "screen_record_enterprise_policies",
+ releasedFlag(
+ name = "enable_screen_record_enterprise_policies",
namespace = DeviceConfig.NAMESPACE_WINDOW_MANAGER,
- teamfood = false
)
// TODO(b/293252410) : Tracking Bug
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/SideFpsProgressBarViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/SideFpsProgressBarViewBinder.kt
index ba4876fff4d1..0bee48a63a28 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/SideFpsProgressBarViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/SideFpsProgressBarViewBinder.kt
@@ -22,6 +22,8 @@ import com.android.systemui.CoreStartable
import com.android.systemui.biometrics.SideFpsController
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.flags.FeatureFlagsClassic
+import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.ui.view.SideFpsProgressBar
import com.android.systemui.keyguard.ui.viewmodel.SideFpsProgressBarViewModel
import com.android.systemui.log.SideFpsLogger
@@ -31,6 +33,7 @@ import com.android.systemui.util.kotlin.Quint
import java.io.PrintWriter
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
@@ -47,15 +50,23 @@ constructor(
private val sfpsController: dagger.Lazy<SideFpsController>,
private val logger: SideFpsLogger,
private val commandRegistry: CommandRegistry,
+ private val featureFlagsClassic: FeatureFlagsClassic,
) : CoreStartable {
override fun start() {
+ if (!featureFlagsClassic.isEnabled(Flags.REST_TO_UNLOCK)) {
+ return
+ }
+ // When the rest to unlock feature is disabled by the user, stop any coroutines that are
+ // not required.
+ var layoutJob: Job? = null
+ var progressJob: Job? = null
commandRegistry.registerCommand(spfsProgressBarCommand) { SfpsProgressBarCommand() }
applicationScope.launch {
viewModel.isProlongedTouchRequiredForAuthentication.collectLatest { enabled ->
logger.isProlongedTouchRequiredForAuthenticationChanged(enabled)
if (enabled) {
- launch {
+ layoutJob = launch {
combine(
viewModel.isVisible,
viewModel.progressBarLocation,
@@ -76,9 +87,13 @@ constructor(
)
}
}
- launch { viewModel.progress.collectLatest { view.setProgress(it) } }
+ progressJob = launch {
+ viewModel.progress.collectLatest { view.setProgress(it) }
+ }
} else {
view.hide()
+ layoutJob?.cancel()
+ progressJob?.cancel()
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt
index f8996b7a8a17..a0f5baff29ba 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt
@@ -26,6 +26,8 @@ import com.android.systemui.biometrics.shared.model.DisplayRotation
import com.android.systemui.biometrics.shared.model.isDefaultOrientation
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.flags.FeatureFlagsClassic
+import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository
import com.android.systemui.keyguard.shared.model.AcquiredFingerprintAuthenticationStatus
import com.android.systemui.keyguard.shared.model.ErrorFingerprintAuthenticationStatus
@@ -34,13 +36,17 @@ import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticati
import com.android.systemui.res.R
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onCompletion
+import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
@SysUISingleton
@@ -52,10 +58,12 @@ constructor(
private val sfpsSensorInteractor: SideFpsSensorInteractor,
displayStateInteractor: DisplayStateInteractor,
@Application private val applicationScope: CoroutineScope,
+ private val featureFlagsClassic: FeatureFlagsClassic,
) {
private val _progress = MutableStateFlow(0.0f)
private val _visible = MutableStateFlow(false)
private var _animator: ValueAnimator? = null
+ private var animatorJob: Job? = null
private fun onFingerprintCaptureCompleted() {
_visible.value = false
@@ -147,26 +155,32 @@ constructor(
sfpsSensorInteractor.isProlongedTouchRequiredForAuthentication
init {
- applicationScope.launch {
- combine(
- sfpsSensorInteractor.isProlongedTouchRequiredForAuthentication,
- sfpsSensorInteractor.authenticationDuration,
- ::Pair
- )
- .collectLatest { (enabled, authDuration) ->
- if (!enabled) return@collectLatest
+ if (featureFlagsClassic.isEnabled(Flags.REST_TO_UNLOCK)) {
+ launchAnimator()
+ }
+ }
- launch {
- fpAuthRepository.authenticationStatus.collectLatest { authStatus ->
+ private fun launchAnimator() {
+ applicationScope.launch {
+ sfpsSensorInteractor.isProlongedTouchRequiredForAuthentication.collectLatest { enabled
+ ->
+ if (!enabled) {
+ animatorJob?.cancel()
+ return@collectLatest
+ }
+ animatorJob =
+ fpAuthRepository.authenticationStatus
+ .onEach { authStatus ->
when (authStatus) {
is AcquiredFingerprintAuthenticationStatus -> {
if (authStatus.fingerprintCaptureStarted) {
-
_visible.value = true
_animator?.cancel()
_animator =
ValueAnimator.ofFloat(0.0f, 1.0f)
- .setDuration(authDuration)
+ .setDuration(
+ sfpsSensorInteractor.authenticationDuration
+ )
.apply {
addUpdateListener {
_progress.value = it.animatedValue as Float
@@ -196,8 +210,9 @@ constructor(
else -> Unit
}
}
- }
- }
+ .onCompletion { _animator?.cancel() }
+ .launchIn(applicationScope)
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
index 7353379b2e79..b1440031a2a0 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
@@ -26,9 +26,12 @@ import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
@@ -105,6 +108,26 @@ constructor(
initialValue = null,
)
+ /**
+ * Whether user input is ongoing for the current transition. For example, if the user is swiping
+ * their finger to transition between scenes, this value will be true while their finger is on
+ * the screen, then false for the rest of the transition.
+ */
+ @OptIn(ExperimentalCoroutinesApi::class)
+ val isTransitionUserInputOngoing: StateFlow<Boolean> =
+ transitionState
+ .flatMapLatest {
+ when (it) {
+ is ObservableTransitionState.Transition -> it.isUserInputOngoing
+ is ObservableTransitionState.Idle -> flowOf(false)
+ }
+ }
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = false
+ )
+
/** Whether the scene container is visible. */
val isVisible: StateFlow<Boolean> = repository.isVisible
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt
index 9ba02b1aa9a8..49bceefb24e0 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt
@@ -17,8 +17,8 @@
package com.android.systemui.scene.shared.flag
import androidx.annotation.VisibleForTesting
-import com.android.systemui.FeatureFlags
import com.android.systemui.Flags as AConfigFlags
+import com.android.systemui.Flags.sceneContainer
import com.android.systemui.compose.ComposeFacade
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FeatureFlagsClassic
@@ -50,7 +50,6 @@ class SceneContainerFlagsImpl
@AssistedInject
constructor(
private val featureFlagsClassic: FeatureFlagsClassic,
- featureFlags: FeatureFlags,
@Assisted private val isComposeAvailable: Boolean,
) : SceneContainerFlags {
@@ -72,7 +71,7 @@ constructor(
listOf(
AconfigFlagMustBeEnabled(
flagName = AConfigFlags.FLAG_SCENE_CONTAINER,
- flagValue = featureFlags.sceneContainer(),
+ flagValue = sceneContainer(),
),
) +
classicFlagTokens.map { flagToken -> FlagMustBeEnabled(flagToken) } +
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/ObservableTransitionState.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/ObservableTransitionState.kt
index 3927873f8ba8..f704894e56e2 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/ObservableTransitionState.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/ObservableTransitionState.kt
@@ -42,6 +42,13 @@ sealed class ObservableTransitionState {
* scene, this value will remain true after the pointer is no longer touching the screen and
* will be true in any transition created to animate back to the original position.
*/
- val isUserInputDriven: Boolean,
+ val isInitiatedByUserInput: Boolean,
+
+ /**
+ * Whether user input is currently driving the transition. For example, if a user is
+ * dragging a pointer, this emits true. Once they lift their finger, this emits false while
+ * the transition completes/settles.
+ */
+ val isUserInputOngoing: Flow<Boolean>,
) : ObservableTransitionState()
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
index a4c4503a6550..b2ffeb3f2925 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
@@ -275,7 +275,7 @@ constructor(
when (state) {
is ObservableTransitionState.Idle -> false
is ObservableTransitionState.Transition ->
- state.isUserInputDriven &&
+ state.isInitiatedByUserInput &&
(state.toScene == sceneKey || state.fromScene == sceneKey)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
index fda4133240c2..225f12536a33 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
@@ -810,6 +810,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
SceneKey.Bouncer,
flowOf(.5f),
false,
+ isUserInputOngoing = flowOf(false),
)
runCurrent()
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer, null), "reason")
@@ -825,7 +826,8 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
SceneKey.Bouncer,
SceneKey.Gone,
flowOf(.5f),
- false
+ false,
+ isUserInputOngoing = flowOf(false),
)
runCurrent()
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Gone, null), "reason")
@@ -842,7 +844,8 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
SceneKey.Gone,
SceneKey.Bouncer,
flowOf(.5f),
- false
+ false,
+ isUserInputOngoing = flowOf(false),
)
runCurrent()
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer, null), "reason")
@@ -860,7 +863,8 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
SceneKey.Bouncer,
SceneKey.Gone,
flowOf(.5f),
- false
+ false,
+ isUserInputOngoing = flowOf(false),
)
runCurrent()
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Gone, null), "reason")
@@ -876,6 +880,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
SceneKey.Lockscreen,
flowOf(.5f),
false,
+ isUserInputOngoing = flowOf(false),
)
runCurrent()
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Lockscreen, null), "reason")
@@ -893,6 +898,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
SceneKey.Gone,
flowOf(.5f),
false,
+ isUserInputOngoing = flowOf(false),
)
runCurrent()
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Gone, null), "reason")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
index 5e7b85779599..2d95b09cbf0e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
@@ -54,6 +54,7 @@ import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.statusbar.VibratorHelper
+import com.android.systemui.statusbar.events.ANIMATING_OUT
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
@@ -211,6 +212,16 @@ open class AuthContainerViewTest : SysuiTestCase() {
}
@Test
+ fun testIgnoresAnimatedInWhenDialogAnimatingOut() {
+ val container = initializeFingerprintContainer(addToView = false)
+ container.mContainerState = ANIMATING_OUT
+ container.addToView()
+ waitForIdleSync()
+
+ verify(callback, never()).onDialogAnimatedIn(anyLong(), anyBoolean())
+ }
+
+ @Test
fun testDismissBeforeIntroEnd() {
val container = initializeFingerprintContainer()
waitForIdleSync()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractorTest.kt
index 3fbdeec70f1f..67d3a20bd5c5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractorTest.kt
@@ -37,8 +37,6 @@ import com.android.systemui.biometrics.shared.model.FingerprintSensorType
import com.android.systemui.biometrics.shared.model.SensorStrength
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.dump.logcatLogBuffer
-import com.android.systemui.flags.FakeFeatureFlagsClassic
-import com.android.systemui.flags.Flags.REST_TO_UNLOCK
import com.android.systemui.log.SideFpsLogger
import com.android.systemui.res.R
import com.android.systemui.util.mockito.whenever
@@ -94,7 +92,6 @@ class SideFpsSensorInteractorTest : SysuiTestCase() {
whenever(displayStateInteractor.currentRotation).thenReturn(currentRotation)
contextDisplayInfo.uniqueId = "current-display"
- val featureFlags = FakeFeatureFlagsClassic().apply { set(REST_TO_UNLOCK, true) }
whenever(fingerprintInteractiveToAuthProvider.enabledForCurrentUser)
.thenReturn(isRestToUnlockEnabled)
underTest =
@@ -103,7 +100,6 @@ class SideFpsSensorInteractorTest : SysuiTestCase() {
fingerprintRepository,
windowManager,
displayStateInteractor,
- featureFlags,
Optional.of(fingerprintInteractiveToAuthProvider),
SideFpsLogger(logcatLogBuffer("SfpsLogger"))
)
@@ -136,7 +132,7 @@ class SideFpsSensorInteractorTest : SysuiTestCase() {
@Test
fun authenticationDurationIsAvailableWhenSFPSSensorIsAvailable() =
testScope.runTest {
- assertThat(collectLastValue(underTest.authenticationDuration)())
+ assertThat(underTest.authenticationDuration)
.isEqualTo(context.resources.getInteger(R.integer.config_restToUnlockDuration))
}
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 f51745b9f17c..b589a2ac8b13 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsClassicDebugTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsClassicDebugTest.kt
@@ -22,7 +22,6 @@ import android.content.pm.PackageManager.NameNotFoundException
import android.content.res.Resources
import android.content.res.Resources.NotFoundException
import android.test.suitebuilder.annotation.SmallTest
-import com.android.systemui.FakeFeatureFlagsImpl
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
@@ -66,7 +65,6 @@ class FeatureFlagsClassicDebugTest : SysuiTestCase() {
private lateinit var broadcastReceiver: BroadcastReceiver
private lateinit var clearCacheAction: Consumer<String>
private val serverFlagReader = ServerFlagReaderFake()
- private val fakeGantryFlags = FakeFeatureFlagsImpl()
private val teamfoodableFlagA = UnreleasedFlag(name = "a", namespace = "test", teamfood = true)
private val teamfoodableFlagB = ReleasedFlag(name = "b", namespace = "test", teamfood = true)
@@ -74,7 +72,6 @@ class FeatureFlagsClassicDebugTest : SysuiTestCase() {
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
- fakeGantryFlags.setFlag("com.android.systemui.sysui_teamfood", false)
flagMap.put(teamfoodableFlagA.name, teamfoodableFlagA)
flagMap.put(teamfoodableFlagB.name, teamfoodableFlagB)
mFeatureFlagsClassicDebug =
@@ -86,7 +83,6 @@ class FeatureFlagsClassicDebugTest : SysuiTestCase() {
resources,
serverFlagReader,
flagMap,
- fakeGantryFlags,
restarter
)
mFeatureFlagsClassicDebug.init()
@@ -134,7 +130,7 @@ class FeatureFlagsClassicDebugTest : SysuiTestCase() {
@Test
fun teamFoodFlag_True() {
- fakeGantryFlags.setFlag("com.android.systemui.sysui_teamfood", true)
+ mSetFlagsRule.enableFlags(com.android.systemui.Flags.FLAG_SYSUI_TEAMFOOD)
assertThat(mFeatureFlagsClassicDebug.isEnabled(teamfoodableFlagA)).isTrue()
assertThat(mFeatureFlagsClassicDebug.isEnabled(teamfoodableFlagB)).isTrue()
@@ -149,7 +145,7 @@ class FeatureFlagsClassicDebugTest : SysuiTestCase() {
.thenReturn(true)
whenever(flagManager.readFlagValue<Boolean>(eq(teamfoodableFlagB.name), any()))
.thenReturn(false)
- fakeGantryFlags.setFlag("com.android.systemui.sysui_teamfood", true)
+ mSetFlagsRule.enableFlags(com.android.systemui.Flags.FLAG_SYSUI_TEAMFOOD)
assertThat(mFeatureFlagsClassicDebug.isEnabled(teamfoodableFlagA)).isTrue()
assertThat(mFeatureFlagsClassicDebug.isEnabled(teamfoodableFlagB)).isFalse()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
index 27325d3f4ecf..ad2ec72468ad 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
@@ -203,7 +203,8 @@ class KeyguardInteractorTest : SysuiTestCase() {
fromScene = SceneKey.Gone,
toScene = SceneKey.Lockscreen,
progress = flowOf(0f),
- isUserInputDriven = false,
+ isInitiatedByUserInput = false,
+ isUserInputOngoing = flowOf(false),
)
runCurrent()
assertThat(isAnimate).isFalse()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
index 88a5c17f4994..9c0456cfdb4c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
@@ -54,6 +54,7 @@ import com.google.common.truth.Truth.assertWithMessage
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
@@ -466,7 +467,8 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() {
fromScene = getCurrentSceneInUi(),
toScene = to.key,
progress = progressFlow,
- isUserInputDriven = false,
+ isInitiatedByUserInput = false,
+ isUserInputOngoing = flowOf(false),
)
runCurrent()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt
index 456f1bcb6f73..d669006c68d3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt
@@ -29,6 +29,7 @@ import com.android.systemui.scene.shared.model.SceneModel
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
@@ -120,7 +121,8 @@ class SceneContainerRepositoryTest : SysuiTestCase() {
fromScene = SceneKey.Lockscreen,
toScene = SceneKey.Shade,
progress = progress,
- isUserInputDriven = false,
+ isInitiatedByUserInput = false,
+ isUserInputOngoing = flowOf(false),
)
assertThat(reflectedTransitionState).isEqualTo(transitionState.value)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
index 8b23d183f1a6..3f032a45df41 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
@@ -83,7 +83,8 @@ class SceneInteractorTest : SysuiTestCase() {
fromScene = SceneKey.Lockscreen,
toScene = SceneKey.Shade,
progress = progress,
- isUserInputDriven = false,
+ isInitiatedByUserInput = false,
+ isUserInputOngoing = flowOf(false),
)
assertThat(reflectedTransitionState).isEqualTo(transitionState.value)
@@ -121,7 +122,8 @@ class SceneInteractorTest : SysuiTestCase() {
fromScene = underTest.desiredScene.value.key,
toScene = SceneKey.Shade,
progress = progress,
- isUserInputDriven = false,
+ isInitiatedByUserInput = false,
+ isUserInputOngoing = flowOf(false),
)
assertThat(transitionTo).isEqualTo(SceneKey.Shade)
@@ -158,7 +160,8 @@ class SceneInteractorTest : SysuiTestCase() {
fromScene = SceneKey.Gone,
toScene = SceneKey.Lockscreen,
progress = flowOf(0.5f),
- isUserInputDriven = false,
+ isInitiatedByUserInput = false,
+ isUserInputOngoing = flowOf(false),
)
)
val transitioning by
@@ -177,7 +180,8 @@ class SceneInteractorTest : SysuiTestCase() {
fromScene = SceneKey.Shade,
toScene = SceneKey.QuickSettings,
progress = flowOf(0.5f),
- isUserInputDriven = false,
+ isInitiatedByUserInput = false,
+ isUserInputOngoing = flowOf(false),
)
)
underTest.setTransitionState(transitionState)
@@ -194,7 +198,8 @@ class SceneInteractorTest : SysuiTestCase() {
fromScene = SceneKey.Shade,
toScene = SceneKey.Lockscreen,
progress = flowOf(0.5f),
- isUserInputDriven = false,
+ isInitiatedByUserInput = false,
+ isUserInputOngoing = flowOf(false),
)
)
val transitioning by
@@ -222,7 +227,8 @@ class SceneInteractorTest : SysuiTestCase() {
fromScene = SceneKey.Shade,
toScene = SceneKey.Lockscreen,
progress = flowOf(0.5f),
- isUserInputDriven = false,
+ isInitiatedByUserInput = false,
+ isUserInputOngoing = flowOf(false),
)
assertThat(transitioning).isTrue()
@@ -231,6 +237,95 @@ class SceneInteractorTest : SysuiTestCase() {
}
@Test
+ fun isTransitionUserInputOngoing_idle_false() =
+ testScope.runTest {
+ val transitionState =
+ MutableStateFlow<ObservableTransitionState>(
+ ObservableTransitionState.Idle(SceneKey.Shade)
+ )
+ val isTransitionUserInputOngoing by
+ collectLastValue(underTest.isTransitionUserInputOngoing)
+ underTest.setTransitionState(transitionState)
+
+ assertThat(isTransitionUserInputOngoing).isFalse()
+ }
+
+ @Test
+ fun isTransitionUserInputOngoing_transition_true() =
+ testScope.runTest {
+ val transitionState =
+ MutableStateFlow<ObservableTransitionState>(
+ ObservableTransitionState.Transition(
+ fromScene = SceneKey.Shade,
+ toScene = SceneKey.Lockscreen,
+ progress = flowOf(0.5f),
+ isInitiatedByUserInput = true,
+ isUserInputOngoing = flowOf(true),
+ )
+ )
+ val isTransitionUserInputOngoing by
+ collectLastValue(underTest.isTransitionUserInputOngoing)
+ underTest.setTransitionState(transitionState)
+
+ assertThat(isTransitionUserInputOngoing).isTrue()
+ }
+
+ @Test
+ fun isTransitionUserInputOngoing_updateMidTransition_false() =
+ testScope.runTest {
+ val transitionState =
+ MutableStateFlow<ObservableTransitionState>(
+ ObservableTransitionState.Transition(
+ fromScene = SceneKey.Shade,
+ toScene = SceneKey.Lockscreen,
+ progress = flowOf(0.5f),
+ isInitiatedByUserInput = true,
+ isUserInputOngoing = flowOf(true),
+ )
+ )
+ val isTransitionUserInputOngoing by
+ collectLastValue(underTest.isTransitionUserInputOngoing)
+ underTest.setTransitionState(transitionState)
+
+ assertThat(isTransitionUserInputOngoing).isTrue()
+
+ transitionState.value =
+ ObservableTransitionState.Transition(
+ fromScene = SceneKey.Shade,
+ toScene = SceneKey.Lockscreen,
+ progress = flowOf(0.6f),
+ isInitiatedByUserInput = true,
+ isUserInputOngoing = flowOf(false),
+ )
+
+ assertThat(isTransitionUserInputOngoing).isFalse()
+ }
+
+ @Test
+ fun isTransitionUserInputOngoing_updateOnIdle_false() =
+ testScope.runTest {
+ val transitionState =
+ MutableStateFlow<ObservableTransitionState>(
+ ObservableTransitionState.Transition(
+ fromScene = SceneKey.Shade,
+ toScene = SceneKey.Lockscreen,
+ progress = flowOf(0.5f),
+ isInitiatedByUserInput = true,
+ isUserInputOngoing = flowOf(true),
+ )
+ )
+ val isTransitionUserInputOngoing by
+ collectLastValue(underTest.isTransitionUserInputOngoing)
+ underTest.setTransitionState(transitionState)
+
+ assertThat(isTransitionUserInputOngoing).isTrue()
+
+ transitionState.value = ObservableTransitionState.Idle(scene = SceneKey.Lockscreen)
+
+ assertThat(isTransitionUserInputOngoing).isFalse()
+ }
+
+ @Test
fun isVisible() =
testScope.runTest {
val isVisible by collectLastValue(underTest.isVisible)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
index c1f2d0cc518f..c0b586195eca 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
@@ -115,7 +115,8 @@ class SceneContainerStartableTest : SysuiTestCase() {
fromScene = SceneKey.Gone,
toScene = SceneKey.Shade,
progress = flowOf(0.5f),
- isUserInputDriven = false,
+ isInitiatedByUserInput = false,
+ isUserInputOngoing = flowOf(false),
)
assertThat(isVisible).isTrue()
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Shade), "reason")
@@ -128,7 +129,8 @@ class SceneContainerStartableTest : SysuiTestCase() {
fromScene = SceneKey.Shade,
toScene = SceneKey.Gone,
progress = flowOf(0.5f),
- isUserInputDriven = false,
+ isInitiatedByUserInput = false,
+ isUserInputOngoing = flowOf(false),
)
assertThat(isVisible).isTrue()
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Gone), "reason")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/shared/flag/SceneContainerFlagsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/shared/flag/SceneContainerFlagsTest.kt
index 0bed4d0d376a..32a38bd1faa1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/shared/flag/SceneContainerFlagsTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/shared/flag/SceneContainerFlagsTest.kt
@@ -76,7 +76,6 @@ internal class SceneContainerFlagsTest(
underTest =
SceneContainerFlagsImpl(
featureFlagsClassic = featureFlags,
- featureFlags = aconfigFlags,
isComposeAvailable = testCase.isComposeAvailable,
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt
index 3a260ae374c6..8b8a62585898 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt
@@ -60,6 +60,7 @@ import dagger.BindsInstance
import dagger.Component
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
@@ -495,7 +496,8 @@ class ShadeInteractorTest : SysuiTestCase() {
fromScene = SceneKey.Lockscreen,
toScene = key,
progress = progress,
- isUserInputDriven = false,
+ isInitiatedByUserInput = false,
+ isUserInputOngoing = flowOf(false),
)
)
sceneInteractor.setTransitionState(transitionState)
@@ -532,7 +534,8 @@ class ShadeInteractorTest : SysuiTestCase() {
fromScene = key,
toScene = SceneKey.Lockscreen,
progress = progress,
- isUserInputDriven = false,
+ isInitiatedByUserInput = false,
+ isUserInputOngoing = flowOf(false),
)
)
sceneInteractor.setTransitionState(transitionState)
@@ -568,7 +571,8 @@ class ShadeInteractorTest : SysuiTestCase() {
fromScene = SceneKey.Lockscreen,
toScene = SceneKey.Shade,
progress = progress,
- isUserInputDriven = false,
+ isInitiatedByUserInput = false,
+ isUserInputOngoing = flowOf(false),
)
)
sceneInteractor.setTransitionState(transitionState)
@@ -844,7 +848,8 @@ class ShadeInteractorTest : SysuiTestCase() {
fromScene = SceneKey.Lockscreen,
toScene = key,
progress = progress,
- isUserInputDriven = false,
+ isInitiatedByUserInput = false,
+ isUserInputOngoing = flowOf(false),
)
)
sceneInteractor.setTransitionState(transitionState)
@@ -881,7 +886,8 @@ class ShadeInteractorTest : SysuiTestCase() {
fromScene = SceneKey.Lockscreen,
toScene = key,
progress = progress,
- isUserInputDriven = true,
+ isInitiatedByUserInput = true,
+ isUserInputOngoing = flowOf(false),
)
)
sceneInteractor.setTransitionState(transitionState)
@@ -918,7 +924,8 @@ class ShadeInteractorTest : SysuiTestCase() {
fromScene = key,
toScene = SceneKey.Lockscreen,
progress = progress,
- isUserInputDriven = false,
+ isInitiatedByUserInput = false,
+ isUserInputOngoing = flowOf(false),
)
)
sceneInteractor.setTransitionState(transitionState)
@@ -955,7 +962,8 @@ class ShadeInteractorTest : SysuiTestCase() {
fromScene = key,
toScene = SceneKey.Lockscreen,
progress = progress,
- isUserInputDriven = true,
+ isInitiatedByUserInput = true,
+ isUserInputOngoing = flowOf(false),
)
)
sceneInteractor.setTransitionState(transitionState)
@@ -990,8 +998,9 @@ class ShadeInteractorTest : SysuiTestCase() {
ObservableTransitionState.Transition(
fromScene = SceneKey.Lockscreen,
toScene = SceneKey.QuickSettings,
- progress = progress,
- isUserInputDriven = true,
+ progress = MutableStateFlow(0f),
+ isInitiatedByUserInput = true,
+ isUserInputOngoing = flowOf(false),
)
)
sceneInteractor.setTransitionState(transitionState)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt
index f98267b63986..02d15de4d953 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt
@@ -20,6 +20,7 @@ import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnec
import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
@@ -89,7 +90,8 @@ class ShadeHeaderViewModelTest : SysuiTestCase() {
fromScene = SceneKey.Shade,
toScene = SceneKey.QuickSettings,
progress = MutableStateFlow(0.5f),
- isUserInputDriven = false,
+ isInitiatedByUserInput = false,
+ isUserInputOngoing = flowOf(false),
)
)
)
@@ -107,7 +109,8 @@ class ShadeHeaderViewModelTest : SysuiTestCase() {
fromScene = SceneKey.QuickSettings,
toScene = SceneKey.Shade,
progress = MutableStateFlow(0.5f),
- isUserInputDriven = false,
+ isInitiatedByUserInput = false,
+ isUserInputOngoing = flowOf(false),
)
)
)
@@ -125,7 +128,8 @@ class ShadeHeaderViewModelTest : SysuiTestCase() {
fromScene = SceneKey.Gone,
toScene = SceneKey.Shade,
progress = MutableStateFlow(0.5f),
- isUserInputDriven = false,
+ isInitiatedByUserInput = false,
+ isUserInputOngoing = flowOf(false),
)
)
)
diff --git a/services/core/java/com/android/server/am/flags.aconfig b/services/core/java/com/android/server/am/flags.aconfig
index cbaf05bb4e23..a770b66b2506 100644
--- a/services/core/java/com/android/server/am/flags.aconfig
+++ b/services/core/java/com/android/server/am/flags.aconfig
@@ -22,3 +22,10 @@ flag {
description: "Detect abusive FGS behavior for certain types (camera, mic, media, location)."
bug: "295545575"
}
+
+flag {
+ name: "fgs_boot_completed"
+ namespace: "backstage_power"
+ description: "Disable BOOT_COMPLETED broadcast FGS start for certain types"
+ bug: "296558535"
+}
diff --git a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
index a6558e07b2aa..eea13f179b9e 100644
--- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
+++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
@@ -14575,9 +14575,10 @@ public class BatteryStatsImpl extends BatteryStats {
mModStepMode = 0;
}
} else {
- if (level >= 90) {
- // If the battery level is at least 90%, always consider the device to be
- // charging even if it happens to go down a level.
+ if (level >= mConstants.BATTERY_CHARGING_ENFORCE_LEVEL) {
+ // If the battery level is at least Constants.BATTERY_CHARGING_ENFORCE_LEVEL,
+ // always consider the device to be charging even if it happens to go down a
+ // level.
changed |= setChargingLocked(true);
} else if (!mCharging) {
if (mLastChargeStepLevel < level) {
@@ -15313,6 +15314,8 @@ public class BatteryStatsImpl extends BatteryStats {
public static final String KEY_MAX_HISTORY_BUFFER_KB = "max_history_buffer_kb";
public static final String KEY_BATTERY_CHARGED_DELAY_MS =
"battery_charged_delay_ms";
+ public static final String KEY_BATTERY_CHARGING_ENFORCE_LEVEL =
+ "battery_charging_enforce_level";
public static final String KEY_PER_UID_MODEM_POWER_MODEL =
"per_uid_modem_power_model";
public static final String KEY_PHONE_ON_EXTERNAL_STATS_COLLECTION =
@@ -15363,6 +15366,7 @@ public class BatteryStatsImpl extends BatteryStats {
private static final int DEFAULT_MAX_HISTORY_FILES_LOW_RAM_DEVICE = 64;
private static final int DEFAULT_MAX_HISTORY_BUFFER_LOW_RAM_DEVICE_KB = 64; /*Kilo Bytes*/
private static final int DEFAULT_BATTERY_CHARGED_DELAY_MS = 900000; /* 15 min */
+ private static final int DEFAULT_BATTERY_CHARGING_ENFORCE_LEVEL = 90;
@PerUidModemPowerModel
private static final int DEFAULT_PER_UID_MODEM_MODEL =
PER_UID_MODEM_POWER_MODEL_MODEM_ACTIVITY_INFO_RX_TX;
@@ -15384,6 +15388,7 @@ public class BatteryStatsImpl extends BatteryStats {
public int MAX_HISTORY_FILES;
public int MAX_HISTORY_BUFFER; /*Bytes*/
public int BATTERY_CHARGED_DELAY_MS = DEFAULT_BATTERY_CHARGED_DELAY_MS;
+ public int BATTERY_CHARGING_ENFORCE_LEVEL = DEFAULT_BATTERY_CHARGING_ENFORCE_LEVEL;
public int PER_UID_MODEM_MODEL = DEFAULT_PER_UID_MODEM_MODEL;
public boolean PHONE_ON_EXTERNAL_STATS_COLLECTION =
DEFAULT_PHONE_ON_EXTERNAL_STATS_COLLECTION;
@@ -15412,6 +15417,9 @@ public class BatteryStatsImpl extends BatteryStats {
mResolver.registerContentObserver(
Settings.Global.getUriFor(Settings.Global.BATTERY_CHARGING_STATE_UPDATE_DELAY),
false /* notifyForDescendants */, this);
+ mResolver.registerContentObserver(Settings.Global.getUriFor(
+ Settings.Global.BATTERY_CHARGING_STATE_ENFORCE_LEVEL),
+ false /* notifyForDescendants */, this);
updateConstants();
}
@@ -15424,6 +15432,12 @@ public class BatteryStatsImpl extends BatteryStats {
updateBatteryChargedDelayMsLocked();
}
return;
+ } else if (uri.equals(Settings.Global.getUriFor(
+ Settings.Global.BATTERY_CHARGING_STATE_ENFORCE_LEVEL))) {
+ synchronized (BatteryStatsImpl.this) {
+ updateBatteryChargingEnforceLevelLocked();
+ }
+ return;
}
updateConstants();
}
@@ -15477,6 +15491,7 @@ public class BatteryStatsImpl extends BatteryStats {
DEFAULT_RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS);
updateBatteryChargedDelayMsLocked();
+ updateBatteryChargingEnforceLevelLocked();
onChange();
}
@@ -15507,6 +15522,21 @@ public class BatteryStatsImpl extends BatteryStats {
}
}
+ private void updateBatteryChargingEnforceLevelLocked() {
+ int lastChargingEnforceLevel = BATTERY_CHARGING_ENFORCE_LEVEL;
+ final int level = Settings.Global.getInt(mResolver,
+ Settings.Global.BATTERY_CHARGING_STATE_ENFORCE_LEVEL,
+ -1);
+
+ BATTERY_CHARGING_ENFORCE_LEVEL = level >= 0 ? level : mParser.getInt(
+ KEY_BATTERY_CHARGING_ENFORCE_LEVEL, DEFAULT_BATTERY_CHARGING_ENFORCE_LEVEL);
+
+ if (BATTERY_CHARGING_ENFORCE_LEVEL <= mLastChargeStepLevel
+ && mLastChargeStepLevel < lastChargingEnforceLevel) {
+ setChargingLocked(true);
+ }
+ }
+
private void updateKernelUidReadersThrottleTime(long oldTimeMs, long newTimeMs) {
KERNEL_UID_READERS_THROTTLE_TIME = newTimeMs;
if (oldTimeMs != newTimeMs) {
@@ -15541,6 +15571,8 @@ public class BatteryStatsImpl extends BatteryStats {
pw.println(MAX_HISTORY_BUFFER/1024);
pw.print(KEY_BATTERY_CHARGED_DELAY_MS); pw.print("=");
pw.println(BATTERY_CHARGED_DELAY_MS);
+ pw.print(KEY_BATTERY_CHARGING_ENFORCE_LEVEL); pw.print("=");
+ pw.println(BATTERY_CHARGING_ENFORCE_LEVEL);
pw.print(KEY_PER_UID_MODEM_POWER_MODEL); pw.print("=");
pw.println(getPerUidModemModelName(PER_UID_MODEM_MODEL));
pw.print(KEY_PHONE_ON_EXTERNAL_STATS_COLLECTION); pw.print("=");
diff --git a/services/core/java/com/android/server/storage/StorageSessionController.java b/services/core/java/com/android/server/storage/StorageSessionController.java
index 4ebd402863c5..5fd787a1f88c 100644
--- a/services/core/java/com/android/server/storage/StorageSessionController.java
+++ b/services/core/java/com/android/server/storage/StorageSessionController.java
@@ -126,10 +126,10 @@ public final class StorageSessionController {
connection = new StorageUserConnection(mContext, userId, this);
mConnections.put(userId, connection);
}
- Slog.i(TAG, "Creating and starting session with id: " + sessionId);
- connection.startSession(sessionId, deviceFd, vol.getPath().getPath(),
- vol.getInternalPath().getPath());
}
+ Slog.i(TAG, "Creating and starting session with id: " + sessionId);
+ connection.startSession(sessionId, deviceFd, vol.getPath().getPath(),
+ vol.getInternalPath().getPath());
}
/**
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 176bc28389e5..a7d77304d046 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -86,6 +86,8 @@ namespace input_flags = com::android::input::flags;
namespace android {
+static const bool ENABLE_POINTER_CHOREOGRAPHER = input_flags::enable_pointer_choreographer();
+
// The exponent used to calculate the pointer speed scaling factor.
// The scaling factor is calculated as 2 ^ (speed * exponent),
// where the speed ranges from -7 to + 7 and is supplied by the user.
@@ -327,6 +329,8 @@ public:
TouchAffineTransformation getTouchAffineTransformation(JNIEnv* env, jfloatArray matrixArr);
void notifyStylusGestureStarted(int32_t deviceId, nsecs_t eventTime) override;
bool isInputMethodConnectionActive() override;
+ std::optional<DisplayViewport> getPointerViewportForAssociatedDisplay(
+ int32_t associatedDisplayId) override;
/* --- InputDispatcherPolicyInterface implementation --- */
@@ -374,8 +378,10 @@ public:
virtual PointerIconStyle getCustomPointerIconId();
virtual void onPointerDisplayIdChanged(int32_t displayId, const FloatPoint& position);
- /* --- PointerControllerPolicyInterface implementation --- */
- std::shared_ptr<PointerControllerInterface> createPointerController() override;
+ /* --- PointerChoreographerPolicyInterface implementation --- */
+ std::shared_ptr<PointerControllerInterface> createPointerController(
+ PointerControllerInterface::ControllerType type) override;
+ void notifyPointerDisplayIdChanged(int32_t displayId, const FloatPoint& position) override;
private:
sp<InputManagerInterface> mInputManager;
@@ -492,7 +498,9 @@ void NativeInputManager::dump(std::string& dump) {
dump += StringPrintf(INDENT "Pointer Capture: %s, seq=%" PRIu32 "\n",
mLocked.pointerCaptureRequest.enable ? "Enabled" : "Disabled",
mLocked.pointerCaptureRequest.seq);
- forEachPointerControllerLocked([&dump](PointerController& pc) { dump += pc.dump(); });
+ if (auto pc = mLocked.legacyPointerController.lock(); pc) {
+ dump += pc->dump();
+ }
} // release lock
dump += "\n";
@@ -537,6 +545,9 @@ void NativeInputManager::setDisplayViewports(JNIEnv* env, jobjectArray viewportO
[&viewports](PointerController& pc) { pc.onDisplayViewportsUpdated(viewports); });
} // release lock
+ if (ENABLE_POINTER_CHOREOGRAPHER) {
+ mInputManager->getChoreographer().setDisplayViewports(viewports);
+ }
mInputManager->getReader().requestRefreshConfiguration(
InputReaderConfiguration::Change::DISPLAY_INFO);
}
@@ -721,6 +732,7 @@ void NativeInputManager::forEachPointerControllerLocked(
continue;
}
apply(*pc);
+ it++;
}
}
@@ -735,9 +747,6 @@ std::shared_ptr<PointerControllerInterface> NativeInputManager::obtainPointerCon
if (controller == nullptr) {
ensureSpriteControllerLocked();
- static const bool ENABLE_POINTER_CHOREOGRAPHER =
- input_flags::enable_pointer_choreographer();
-
// Disable the functionality of the legacy PointerController if PointerChoreographer is
// enabled.
controller = PointerController::create(this, mLooper, *mLocked.spriteController,
@@ -749,17 +758,43 @@ std::shared_ptr<PointerControllerInterface> NativeInputManager::obtainPointerCon
return controller;
}
-std::shared_ptr<PointerControllerInterface> NativeInputManager::createPointerController() {
+std::shared_ptr<PointerControllerInterface> NativeInputManager::createPointerController(
+ PointerControllerInterface::ControllerType type) {
std::scoped_lock _l(mLock);
ensureSpriteControllerLocked();
std::shared_ptr<PointerController> pc =
- PointerController::create(this, mLooper, *mLocked.spriteController, /*enabled=*/true);
+ PointerController::create(this, mLooper, *mLocked.spriteController, /*enabled=*/true,
+ type);
mLocked.pointerControllers.emplace_back(pc);
return pc;
}
void NativeInputManager::onPointerDisplayIdChanged(int32_t pointerDisplayId,
const FloatPoint& position) {
+ if (ENABLE_POINTER_CHOREOGRAPHER) {
+ return;
+ }
+ JNIEnv* env = jniEnv();
+ env->CallVoidMethod(mServiceObj, gServiceClassInfo.onPointerDisplayIdChanged, pointerDisplayId,
+ position.x, position.y);
+ checkAndClearExceptionFromCallback(env, "onPointerDisplayIdChanged");
+}
+
+void NativeInputManager::notifyPointerDisplayIdChanged(int32_t pointerDisplayId,
+ const FloatPoint& position) {
+ // Notify the Reader so that devices can be reconfigured.
+ { // acquire lock
+ std::scoped_lock _l(mLock);
+ if (mLocked.pointerDisplayId == pointerDisplayId) {
+ return;
+ }
+ mLocked.pointerDisplayId = pointerDisplayId;
+ ALOGI("%s: pointer displayId set to: %d", __func__, pointerDisplayId);
+ } // release lock
+ mInputManager->getReader().requestRefreshConfiguration(
+ InputReaderConfiguration::Change::DISPLAY_INFO);
+
+ // Notify the system.
JNIEnv* env = jniEnv();
env->CallVoidMethod(mServiceObj, gServiceClassInfo.onPointerDisplayIdChanged, pointerDisplayId,
position.x, position.y);
@@ -1118,19 +1153,23 @@ void NativeInputManager::updateInactivityTimeoutLocked() REQUIRES(mLock) {
}
void NativeInputManager::setPointerDisplayId(int32_t displayId) {
- { // acquire lock
- std::scoped_lock _l(mLock);
+ if (ENABLE_POINTER_CHOREOGRAPHER) {
+ mInputManager->getChoreographer().setDefaultMouseDisplayId(displayId);
+ } else {
+ { // acquire lock
+ std::scoped_lock _l(mLock);
- if (mLocked.pointerDisplayId == displayId) {
- return;
- }
+ if (mLocked.pointerDisplayId == displayId) {
+ return;
+ }
- ALOGI("Setting pointer display id to %d.", displayId);
- mLocked.pointerDisplayId = displayId;
- } // release lock
+ ALOGI("Setting pointer display id to %d.", displayId);
+ mLocked.pointerDisplayId = displayId;
+ } // release lock
- mInputManager->getReader().requestRefreshConfiguration(
- InputReaderConfiguration::Change::DISPLAY_INFO);
+ mInputManager->getReader().requestRefreshConfiguration(
+ InputReaderConfiguration::Change::DISPLAY_INFO);
+ }
}
void NativeInputManager::setPointerSpeed(int32_t speed) {
@@ -1356,6 +1395,11 @@ bool NativeInputManager::isInputMethodConnectionActive() {
return result;
}
+std::optional<DisplayViewport> NativeInputManager::getPointerViewportForAssociatedDisplay(
+ int32_t associatedDisplayId) {
+ return mInputManager->getChoreographer().getViewportForPointerDevice(associatedDisplayId);
+}
+
bool NativeInputManager::filterInputEvent(const InputEvent& inputEvent, uint32_t policyFlags) {
ATRACE_CALL();
JNIEnv* env = jniEnv();
@@ -1689,6 +1733,9 @@ void NativeInputManager::setStylusButtonMotionEventsEnabled(bool enabled) {
}
FloatPoint NativeInputManager::getMouseCursorPosition() {
+ if (ENABLE_POINTER_CHOREOGRAPHER) {
+ return mInputManager->getChoreographer().getMouseCursorPosition(ADISPLAY_ID_NONE);
+ }
std::scoped_lock _l(mLock);
const auto pc = mLocked.legacyPointerController.lock();
if (!pc) return {AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION};
diff --git a/services/permission/java/com/android/server/permission/access/AccessCheckingService.kt b/services/permission/java/com/android/server/permission/access/AccessCheckingService.kt
index 93530cf5b0a9..acaec211440d 100644
--- a/services/permission/java/com/android/server/permission/access/AccessCheckingService.kt
+++ b/services/permission/java/com/android/server/permission/access/AccessCheckingService.kt
@@ -16,7 +16,6 @@
package com.android.server.permission.access
-import android.app.admin.DevicePolicyManagerInternal
import android.content.Context
import android.content.pm.PackageManager
import android.content.pm.PackageManagerInternal
@@ -75,7 +74,7 @@ class AccessCheckingService(context: Context) : SystemService(context) {
val userIds = MutableIntSet(userManagerService.userIdsIncludingPreCreated)
val (packageStates, disabledSystemPackageStates) = packageManagerLocal.allPackageStates
- val knownPackages = packageManagerInternal.getKnownPackages(packageStates)
+ val knownPackages = packageManagerInternal.knownPackages
val isLeanback = systemConfig.isLeanback
val configPermissions = systemConfig.permissions
val privilegedPermissionAllowlistPackages =
@@ -152,7 +151,7 @@ class AccessCheckingService(context: Context) : SystemService(context) {
isSystemUpdated: Boolean
) {
val (packageStates, disabledSystemPackageStates) = packageManagerLocal.allPackageStates
- val knownPackages = packageManagerInternal.getKnownPackages(packageStates)
+ val knownPackages = packageManagerInternal.knownPackages
mutateState {
with(policy) {
onStorageVolumeMounted(
@@ -169,7 +168,7 @@ class AccessCheckingService(context: Context) : SystemService(context) {
internal fun onPackageAdded(packageName: String) {
val (packageStates, disabledSystemPackageStates) = packageManagerLocal.allPackageStates
- val knownPackages = packageManagerInternal.getKnownPackages(packageStates)
+ val knownPackages = packageManagerInternal.knownPackages
mutateState {
with(policy) {
onPackageAdded(
@@ -184,7 +183,7 @@ class AccessCheckingService(context: Context) : SystemService(context) {
internal fun onPackageRemoved(packageName: String, appId: Int) {
val (packageStates, disabledSystemPackageStates) = packageManagerLocal.allPackageStates
- val knownPackages = packageManagerInternal.getKnownPackages(packageStates)
+ val knownPackages = packageManagerInternal.knownPackages
mutateState {
with(policy) {
onPackageRemoved(
@@ -200,7 +199,7 @@ class AccessCheckingService(context: Context) : SystemService(context) {
internal fun onPackageInstalled(packageName: String, userId: Int) {
val (packageStates, disabledSystemPackageStates) = packageManagerLocal.allPackageStates
- val knownPackages = packageManagerInternal.getKnownPackages(packageStates)
+ val knownPackages = packageManagerInternal.knownPackages
mutateState {
with(policy) {
onPackageInstalled(
@@ -216,7 +215,7 @@ class AccessCheckingService(context: Context) : SystemService(context) {
internal fun onPackageUninstalled(packageName: String, appId: Int, userId: Int) {
val (packageStates, disabledSystemPackageStates) = packageManagerLocal.allPackageStates
- val knownPackages = packageManagerInternal.getKnownPackages(packageStates)
+ val knownPackages = packageManagerInternal.knownPackages
mutateState {
with(policy) {
onPackageUninstalled(
@@ -232,69 +231,50 @@ class AccessCheckingService(context: Context) : SystemService(context) {
}
internal fun onSystemReady() {
- val (packageStates, disabledSystemPackageStates) = packageManagerLocal.allPackageStates
- val knownPackages = packageManagerInternal.getKnownPackages(packageStates)
- mutateState {
- with(policy) {
- onSystemReady(packageStates, disabledSystemPackageStates, knownPackages)
- }
- }
+ mutateState { with(policy) { onSystemReady() } }
}
private val PackageManagerLocal.allPackageStates:
Pair<Map<String, PackageState>, Map<String, PackageState>>
get() = withUnfilteredSnapshot().use { it.packageStates to it.disabledSystemPackageStates }
- private fun PackageManagerInternal.getKnownPackages(
- packageStates: Map<String, PackageState>
- ): IntMap<Array<String>> =
- MutableIntMap<Array<String>>().apply {
- this[KnownPackages.PACKAGE_INSTALLER] =
- getKnownPackageNames(KnownPackages.PACKAGE_INSTALLER, UserHandle.USER_SYSTEM)
- this[KnownPackages.PACKAGE_PERMISSION_CONTROLLER] =
- getKnownPackageNames(
- KnownPackages.PACKAGE_PERMISSION_CONTROLLER,
- UserHandle.USER_SYSTEM
+ private val PackageManagerInternal.knownPackages: IntMap<Array<String>>
+ get() =
+ MutableIntMap<Array<String>>().apply {
+ this[KnownPackages.PACKAGE_INSTALLER] = getKnownPackageNames(
+ KnownPackages.PACKAGE_INSTALLER, UserHandle.USER_SYSTEM
)
- this[KnownPackages.PACKAGE_VERIFIER] =
- getKnownPackageNames(KnownPackages.PACKAGE_VERIFIER, UserHandle.USER_SYSTEM)
- this[KnownPackages.PACKAGE_SETUP_WIZARD] =
- getKnownPackageNames(KnownPackages.PACKAGE_SETUP_WIZARD, UserHandle.USER_SYSTEM)
- this[KnownPackages.PACKAGE_SYSTEM_TEXT_CLASSIFIER] =
- getKnownPackageNames(
- KnownPackages.PACKAGE_SYSTEM_TEXT_CLASSIFIER,
- UserHandle.USER_SYSTEM
+ this[KnownPackages.PACKAGE_PERMISSION_CONTROLLER] = getKnownPackageNames(
+ KnownPackages.PACKAGE_PERMISSION_CONTROLLER, UserHandle.USER_SYSTEM
)
- this[KnownPackages.PACKAGE_CONFIGURATOR] =
- getKnownPackageNames(KnownPackages.PACKAGE_CONFIGURATOR, UserHandle.USER_SYSTEM)
- this[KnownPackages.PACKAGE_INCIDENT_REPORT_APPROVER] =
- getKnownPackageNames(
- KnownPackages.PACKAGE_INCIDENT_REPORT_APPROVER,
- UserHandle.USER_SYSTEM
+ this[KnownPackages.PACKAGE_VERIFIER] = getKnownPackageNames(
+ KnownPackages.PACKAGE_VERIFIER, UserHandle.USER_SYSTEM
)
- this[KnownPackages.PACKAGE_APP_PREDICTOR] =
- getKnownPackageNames(KnownPackages.PACKAGE_APP_PREDICTOR, UserHandle.USER_SYSTEM)
- this[KnownPackages.PACKAGE_COMPANION] =
- getKnownPackageNames(KnownPackages.PACKAGE_COMPANION, UserHandle.USER_SYSTEM)
- this[KnownPackages.PACKAGE_RETAIL_DEMO] =
- getKnownPackageNames(KnownPackages.PACKAGE_RETAIL_DEMO, UserHandle.USER_SYSTEM)
- .filter { isProfileOwner(it, packageStates) }
- .toTypedArray()
- this[KnownPackages.PACKAGE_RECENTS] =
- getKnownPackageNames(KnownPackages.PACKAGE_RECENTS, UserHandle.USER_SYSTEM)
- }
-
- private fun isProfileOwner(
- packageName: String,
- packageStates: Map<String, PackageState>
- ): Boolean {
- val appId = packageStates[packageName]?.appId ?: return false
- val devicePolicyManagerInternal =
- LocalServices.getService(DevicePolicyManagerInternal::class.java) ?: return false
- // TODO(b/169395065): Figure out if this flow makes sense in Device Owner mode.
- return devicePolicyManagerInternal.isActiveProfileOwner(appId) ||
- devicePolicyManagerInternal.isActiveDeviceOwner(appId)
- }
+ this[KnownPackages.PACKAGE_SETUP_WIZARD] = getKnownPackageNames(
+ KnownPackages.PACKAGE_SETUP_WIZARD, UserHandle.USER_SYSTEM
+ )
+ this[KnownPackages.PACKAGE_SYSTEM_TEXT_CLASSIFIER] = getKnownPackageNames(
+ KnownPackages.PACKAGE_SYSTEM_TEXT_CLASSIFIER, UserHandle.USER_SYSTEM
+ )
+ this[KnownPackages.PACKAGE_CONFIGURATOR] = getKnownPackageNames(
+ KnownPackages.PACKAGE_CONFIGURATOR, UserHandle.USER_SYSTEM
+ )
+ this[KnownPackages.PACKAGE_INCIDENT_REPORT_APPROVER] = getKnownPackageNames(
+ KnownPackages.PACKAGE_INCIDENT_REPORT_APPROVER, UserHandle.USER_SYSTEM
+ )
+ this[KnownPackages.PACKAGE_APP_PREDICTOR] = getKnownPackageNames(
+ KnownPackages.PACKAGE_APP_PREDICTOR, UserHandle.USER_SYSTEM
+ )
+ this[KnownPackages.PACKAGE_COMPANION] = getKnownPackageNames(
+ KnownPackages.PACKAGE_COMPANION, UserHandle.USER_SYSTEM
+ )
+ this[KnownPackages.PACKAGE_RETAIL_DEMO] = getKnownPackageNames(
+ KnownPackages.PACKAGE_RETAIL_DEMO, UserHandle.USER_SYSTEM
+ )
+ this[KnownPackages.PACKAGE_RECENTS] = getKnownPackageNames(
+ KnownPackages.PACKAGE_RECENTS, UserHandle.USER_SYSTEM
+ )
+ }
@OptIn(ExperimentalContracts::class)
internal inline fun <T> getState(action: GetStateScope.() -> T): T {
diff --git a/services/permission/java/com/android/server/permission/access/AccessPolicy.kt b/services/permission/java/com/android/server/permission/access/AccessPolicy.kt
index 754f77ec38f9..29fe95c1e252 100644
--- a/services/permission/java/com/android/server/permission/access/AccessPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/AccessPolicy.kt
@@ -262,17 +262,8 @@ private constructor(
forEachSchemePolicy { with(it) { onPackageUninstalled(packageName, appId, userId) } }
}
- fun MutateStateScope.onSystemReady(
- packageStates: Map<String, PackageState>,
- disabledSystemPackageStates: Map<String, PackageState>,
- knownPackages: IntMap<Array<String>>
- ) {
- newState.mutateExternalState().apply {
- setPackageStates(packageStates)
- setDisabledSystemPackageStates(disabledSystemPackageStates)
- setKnownPackages(knownPackages)
- setSystemReady(true)
- }
+ fun MutateStateScope.onSystemReady() {
+ newState.mutateExternalState().setSystemReady(true)
forEachSchemePolicy { with(it) { onSystemReady() } }
}
diff --git a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
index 08ba75397a09..010604f9aaaa 100644
--- a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
@@ -1448,15 +1448,6 @@ class AppIdPermissionPolicy : SchemePolicy() {
// Special permissions for the system companion device manager.
return true
}
- if (
- permission.isRetailDemo &&
- packageName in knownPackages[KnownPackages.PACKAGE_RETAIL_DEMO]!!
- ) {
- // Special permission granted only to the OEM specified retail demo app.
- // Note that the original code was passing app ID as UID, so this behavior is kept
- // unchanged.
- return true
- }
if (permission.isRecents && packageName in knownPackages[KnownPackages.PACKAGE_RECENTS]!!) {
// Special permission for the recents app.
return true
@@ -1511,27 +1502,6 @@ class AppIdPermissionPolicy : SchemePolicy() {
}
override fun MutateStateScope.onSystemReady() {
- // HACK: PACKAGE_USAGE_STATS is the only permission with the retailDemo protection flag,
- // and we have to wait until DevicePolicyManagerService is started to know whether the
- // retail demo package is a profile owner so that it can have the permission.
- // Since there's no simple callback for profile owner change, and we are deprecating and
- // removing the retailDemo protection flag in favor of a proper role soon, we can just
- // re-evaluate the permission here, which is also how the old implementation has been
- // working.
- // TODO: Partially revert ag/22690114 once we can remove support for the retailDemo
- // protection flag.
- val externalState = newState.externalState
- for (packageName in externalState.knownPackages[KnownPackages.PACKAGE_RETAIL_DEMO]!!) {
- val appId = externalState.packageStates[packageName]?.appId ?: continue
- newState.userStates.forEachIndexed { _, userId, _ ->
- evaluatePermissionState(
- appId,
- userId,
- Manifest.permission.PACKAGE_USAGE_STATS,
- null
- )
- }
- }
if (!privilegedPermissionAllowlistViolations.isEmpty()) {
throw IllegalStateException(
"Signature|privileged permissions not in privileged" +
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
index dd23d9f006e3..e5291d31d524 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
@@ -577,8 +577,14 @@ public class JobSchedulerServiceTest {
JobStatus jobUIDT = createJobStatus("testGetMaxJobExecutionTimeMs",
createJobInfo(10)
.setUserInitiated(true).setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY));
+ JobStatus jobEj = createJobStatus("testGetMaxJobExecutionTimeMs",
+ createJobInfo(2).setExpedited(true));
+ JobStatus jobReg = createJobStatus("testGetMaxJobExecutionTimeMs",
+ createJobInfo(3));
spyOn(jobUIDT);
when(jobUIDT.shouldTreatAsUserInitiatedJob()).thenReturn(true);
+ spyOn(jobEj);
+ when(jobEj.shouldTreatAsExpeditedJob()).thenReturn(true);
QuotaController quotaController = mService.getQuotaController();
spyOn(quotaController);
@@ -595,6 +601,11 @@ public class JobSchedulerServiceTest {
grantRunUserInitiatedJobsPermission(false);
assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
mService.getMaxJobExecutionTimeMs(jobUIDT));
+
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
+ mService.getMaxJobExecutionTimeMs(jobEj));
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobReg));
}
@Test
@@ -636,7 +647,7 @@ public class JobSchedulerServiceTest {
grantRunUserInitiatedJobsPermission(false);
assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
mService.getMaxJobExecutionTimeMs(jobUij));
- assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
mService.getMaxJobExecutionTimeMs(jobEj));
assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
mService.getMaxJobExecutionTimeMs(jobReg));
@@ -649,7 +660,7 @@ public class JobSchedulerServiceTest {
grantRunUserInitiatedJobsPermission(false);
assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
mService.getMaxJobExecutionTimeMs(jobUij));
- assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
mService.getMaxJobExecutionTimeMs(jobEj));
assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
mService.getMaxJobExecutionTimeMs(jobReg));
@@ -664,7 +675,7 @@ public class JobSchedulerServiceTest {
grantRunUserInitiatedJobsPermission(false);
assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
mService.getMaxJobExecutionTimeMs(jobUij));
- assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
mService.getMaxJobExecutionTimeMs(jobEj));
assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
mService.getMaxJobExecutionTimeMs(jobReg));
@@ -677,7 +688,7 @@ public class JobSchedulerServiceTest {
grantRunUserInitiatedJobsPermission(false);
assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
mService.getMaxJobExecutionTimeMs(jobUij));
- assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
mService.getMaxJobExecutionTimeMs(jobEj));
assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
mService.getMaxJobExecutionTimeMs(jobReg));
@@ -692,7 +703,7 @@ public class JobSchedulerServiceTest {
grantRunUserInitiatedJobsPermission(false);
assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
mService.getMaxJobExecutionTimeMs(jobUij));
- assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
mService.getMaxJobExecutionTimeMs(jobEj));
assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
mService.getMaxJobExecutionTimeMs(jobReg));
@@ -705,7 +716,7 @@ public class JobSchedulerServiceTest {
grantRunUserInitiatedJobsPermission(false);
assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
mService.getMaxJobExecutionTimeMs(jobUij));
- assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
mService.getMaxJobExecutionTimeMs(jobEj));
assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
mService.getMaxJobExecutionTimeMs(jobReg));
@@ -720,7 +731,7 @@ public class JobSchedulerServiceTest {
grantRunUserInitiatedJobsPermission(false);
assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
mService.getMaxJobExecutionTimeMs(jobUij));
- assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
mService.getMaxJobExecutionTimeMs(jobEj));
assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
mService.getMaxJobExecutionTimeMs(jobReg));
@@ -765,7 +776,7 @@ public class JobSchedulerServiceTest {
grantRunUserInitiatedJobsPermission(false);
assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
mService.getMaxJobExecutionTimeMs(jobUij));
- assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
mService.getMaxJobExecutionTimeMs(jobEj));
assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
mService.getMaxJobExecutionTimeMs(jobReg));
@@ -778,7 +789,7 @@ public class JobSchedulerServiceTest {
grantRunUserInitiatedJobsPermission(false);
assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
mService.getMaxJobExecutionTimeMs(jobUij));
- assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
mService.getMaxJobExecutionTimeMs(jobEj));
assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
mService.getMaxJobExecutionTimeMs(jobReg));
@@ -792,7 +803,7 @@ public class JobSchedulerServiceTest {
grantRunUserInitiatedJobsPermission(false);
assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
mService.getMaxJobExecutionTimeMs(jobUij));
- assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
mService.getMaxJobExecutionTimeMs(jobEj));
assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
mService.getMaxJobExecutionTimeMs(jobReg));
@@ -807,7 +818,7 @@ public class JobSchedulerServiceTest {
grantRunUserInitiatedJobsPermission(false);
assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
mService.getMaxJobExecutionTimeMs(jobUij));
- assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
mService.getMaxJobExecutionTimeMs(jobEj));
assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
mService.getMaxJobExecutionTimeMs(jobReg));
@@ -820,7 +831,7 @@ public class JobSchedulerServiceTest {
grantRunUserInitiatedJobsPermission(false);
assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
mService.getMaxJobExecutionTimeMs(jobUij));
- assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
mService.getMaxJobExecutionTimeMs(jobEj));
assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
mService.getMaxJobExecutionTimeMs(jobReg));
@@ -834,7 +845,7 @@ public class JobSchedulerServiceTest {
grantRunUserInitiatedJobsPermission(false);
assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
mService.getMaxJobExecutionTimeMs(jobUij));
- assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
mService.getMaxJobExecutionTimeMs(jobEj));
assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
mService.getMaxJobExecutionTimeMs(jobReg));