summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java3
-rw-r--r--apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java28
-rw-r--r--cmds/statsd/src/OWNERS6
-rw-r--r--core/api/system-current.txt5
-rw-r--r--core/java/android/app/BroadcastOptions.java4
-rw-r--r--core/java/android/app/Notification.java10
-rw-r--r--core/java/android/app/Service.java4
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java2
-rw-r--r--core/java/android/bluetooth/BluetoothCodecStatus.java9
-rw-r--r--core/java/android/companion/OWNERS1
-rw-r--r--core/java/android/content/Context.java14
-rw-r--r--core/java/android/content/pm/PermissionInfo.java14
-rw-r--r--core/java/android/hardware/biometrics/SensorPropertiesInternal.java16
-rw-r--r--core/java/android/hardware/display/DisplayManagerGlobal.java4
-rw-r--r--core/java/android/hardware/face/FaceSensorPropertiesInternal.java6
-rw-r--r--core/java/android/os/BatteryStats.java23
-rw-r--r--core/java/android/security/keymaster/KeymasterDefs.java2
-rw-r--r--core/java/android/view/Choreographer.java4
-rw-r--r--core/java/android/view/Display.java32
-rw-r--r--core/java/android/view/DisplayEventReceiver.java64
-rw-r--r--core/java/android/view/DisplayInfo.java25
-rw-r--r--core/java/android/webkit/PacProcessor.java2
-rw-r--r--core/java/android/widget/SelectionActionModeHelper.java33
-rw-r--r--core/java/android/window/DisplayAreaOrganizer.java57
-rw-r--r--core/java/android/window/IDisplayAreaOrganizerController.aidl25
-rw-r--r--core/java/com/android/internal/content/FileSystemProvider.java64
-rw-r--r--core/java/com/android/internal/infra/AbstractMultiplePendingRequestsRemoteService.java3
-rw-r--r--core/java/com/android/internal/infra/AbstractRemoteService.java3
-rw-r--r--core/java/com/android/internal/infra/AbstractSinglePendingRequestRemoteService.java3
-rw-r--r--core/java/com/android/internal/infra/OWNERS6
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java221
-rw-r--r--core/java/com/android/internal/power/MeasuredEnergyArray.java66
-rw-r--r--core/java/com/android/internal/power/MeasuredEnergyStats.java307
-rw-r--r--core/java/com/android/internal/util/function/pooled/OWNERS1
-rw-r--r--core/jni/android_view_DisplayEventReceiver.cpp80
-rw-r--r--core/proto/OWNERS15
-rw-r--r--core/proto/android/server/accessibility.proto27
-rw-r--r--core/proto/android/server/accessibilitytrace.proto62
-rw-r--r--core/res/AndroidManifest.xml4
-rw-r--r--core/res/res/values/attrs_manifest.xml3
-rw-r--r--core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java9
-rw-r--r--core/tests/coretests/src/android/graphics/TypefaceTest.java8
-rw-r--r--core/tests/coretests/src/android/text/FontFallbackSetup.java5
-rw-r--r--core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java4
-rw-r--r--core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java278
-rw-r--r--core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerStatsData.java43
-rw-r--r--core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerStatsViewerActivity.java6
-rw-r--r--data/etc/com.android.provision.xml2
-rw-r--r--data/etc/services.core.protolog.json24
-rw-r--r--graphics/java/android/graphics/HardwareRenderer.java2
-rw-r--r--graphics/java/android/graphics/Typeface.java6
-rw-r--r--graphics/java/android/graphics/fonts/SystemFonts.java88
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt4
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt6
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt96
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvUtils.kt3
-rw-r--r--libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_pip.xml6
-rw-r--r--libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/PipActivity.java109
-rw-r--r--media/java/android/media/Rating.java11
-rw-r--r--packages/SettingsLib/Utils/src/com/android/settingslib/utils/applications/AppUtils.java3
-rw-r--r--packages/Shell/AndroidManifest.xml1
-rw-r--r--packages/SystemUI/Android.bp7
-rw-r--r--packages/SystemUI/plugin/Android.bp3
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java58
-rw-r--r--packages/SystemUI/res/values/strings.xml2
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java121
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java152
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java321
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java (renamed from packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingDataProvider.java)113
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java145
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java202
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java31
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java268
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/brightline/DiagonalClassifier.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/brightline/DistanceClassifier.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/brightline/DoubleTapClassifier.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingClassifier.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/brightline/PointerCountClassifier.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/brightline/ProximityClassifier.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/brightline/SingleTapClassifier.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/brightline/TimeLimitedMotionEventBuffer.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/brightline/TypeClassifier.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeFalsingManagerAdapter.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java31
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java85
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java29
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/classifier/ClassifierTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ClassifierTest.java)24
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/BrightLineFalsingManagerTest.java)93
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/FalsingDataProviderTest.java)11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DiagonalClassifierTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DistanceClassifierTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DoubleTapClassifierTest.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/PointerCountClassifierTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ProximityClassifierTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/SingleTapClassifierTest.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/TypeClassifierTest.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ZigZagClassifierTest.java1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java31
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java19
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java16
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java2
-rw-r--r--packages/services/PacProcessor/AndroidManifest.xml1
-rw-r--r--services/companion/java/com/android/server/companion/OWNERS1
-rw-r--r--services/core/java/android/app/usage/UsageStatsManagerInternal.java14
-rw-r--r--services/core/java/android/content/pm/PackageManagerInternal.java6
-rw-r--r--services/core/java/com/android/server/PackageWatchdog.java60
-rw-r--r--services/core/java/com/android/server/RescueParty.java41
-rw-r--r--services/core/java/com/android/server/am/ActiveInstrumentation.java5
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java242
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java18
-rw-r--r--services/core/java/com/android/server/am/BatteryExternalStatsWorker.java35
-rw-r--r--services/core/java/com/android/server/am/BatteryStatsService.java63
-rw-r--r--services/core/java/com/android/server/am/ProcessRecord.java14
-rw-r--r--services/core/java/com/android/server/am/ServiceRecord.java47
-rw-r--r--services/core/java/com/android/server/biometrics/BiometricService.java6
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java12
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/TestSession.java3
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java43
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/TestSession.java23
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java2
-rw-r--r--services/core/java/com/android/server/display/DisplayDeviceInfo.java12
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java164
-rw-r--r--services/core/java/com/android/server/display/LocalDisplayAdapter.java63
-rw-r--r--services/core/java/com/android/server/display/LogicalDisplay.java71
-rw-r--r--services/core/java/com/android/server/display/LogicalDisplayMapper.java7
-rw-r--r--services/core/java/com/android/server/display/OverlayDisplayWindow.java8
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java127
-rw-r--r--services/core/java/com/android/server/pm/permission/Permission.java4
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java57
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java52
-rw-r--r--services/core/java/com/android/server/powerstats/PowerStatsHALWrapper.java106
-rw-r--r--services/core/java/com/android/server/powerstats/PowerStatsLogger.java5
-rw-r--r--services/core/java/com/android/server/powerstats/PowerStatsService.java6
-rw-r--r--services/core/java/com/android/server/powerstats/ProtoStreamUtils.java68
-rw-r--r--services/core/java/com/android/server/wm/DisplayArea.java7
-rw-r--r--services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java152
-rw-r--r--services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java6
-rw-r--r--services/core/java/com/android/server/wm/RootDisplayArea.java5
-rw-r--r--services/core/java/com/android/server/wm/TaskDisplayArea.java17
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java42
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java17
-rw-r--r--services/tests/mockingservicestests/Android.bp1
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java68
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/usage/UsageStatsServiceTest.java134
-rw-r--r--services/tests/servicestests/Android.bp2
-rw-r--r--services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java379
-rw-r--r--services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java50
-rw-r--r--services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java12
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayAreaOrganizerTest.java149
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java68
-rw-r--r--tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java31
-rw-r--r--tests/net/common/java/android/net/MatchAllNetworkSpecifierTest.kt9
-rw-r--r--tools/codegen/src/com/android/codegen/Generators.kt9
-rw-r--r--tools/codegen/src/com/android/codegen/SharedConstants.kt2
-rwxr-xr-xtools/hiddenapi/exclude.sh2
-rw-r--r--wifi/java/android/net/wifi/SoftApConfiguration.java9
-rw-r--r--wifi/java/android/net/wifi/SoftApInfo.java9
184 files changed, 5006 insertions, 1564 deletions
diff --git a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
index 398ccb69fbe8..2ce85ee57205 100644
--- a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
+++ b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
@@ -3,7 +3,6 @@ package com.android.server.usage;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.app.usage.AppStandbyInfo;
-import android.app.usage.UsageEvents;
import android.app.usage.UsageStatsManager.StandbyBuckets;
import android.app.usage.UsageStatsManager.SystemForcedReasons;
import android.content.Context;
@@ -68,8 +67,6 @@ public interface AppStandbyInternal {
*/
void postOneTimeCheckIdleStates();
- void reportEvent(UsageEvents.Event event, int userId);
-
void setLastJobRunTime(String packageName, int userId, long elapsedRealtime);
long getTimeSinceLastJobRun(String packageName, int userId);
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index 1157ee905b86..0b0923a67de6 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -62,6 +62,7 @@ import android.app.usage.AppStandbyInfo;
import android.app.usage.UsageEvents;
import android.app.usage.UsageStatsManager.StandbyBuckets;
import android.app.usage.UsageStatsManager.SystemForcedReasons;
+import android.app.usage.UsageStatsManagerInternal;
import android.appwidget.AppWidgetManager;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
@@ -128,9 +129,10 @@ import java.util.concurrent.CountDownLatch;
* Manages the standby state of an app, listening to various events.
*
* Unit test:
- atest com.android.server.usage.AppStandbyControllerTests
+ * atest com.android.server.usage.AppStandbyControllerTests
*/
-public class AppStandbyController implements AppStandbyInternal {
+public class AppStandbyController
+ implements AppStandbyInternal, UsageStatsManagerInternal.UsageEventListener {
private static final String TAG = "AppStandbyController";
// Do not submit with true.
@@ -468,10 +470,21 @@ public class AppStandbyController implements AppStandbyInternal {
@VisibleForTesting
void setAppIdleEnabled(boolean enabled) {
+ // Don't call out to USM with the lock held. Also, register the listener before we
+ // change our internal state so no events fall through the cracks.
+ final UsageStatsManagerInternal usmi =
+ LocalServices.getService(UsageStatsManagerInternal.class);
+ if (enabled) {
+ usmi.registerListener(this);
+ } else {
+ usmi.unregisterListener(this);
+ }
+
synchronized (mAppIdleLock) {
if (mAppIdleEnabled != enabled) {
final boolean oldParoleState = isInParole();
mAppIdleEnabled = enabled;
+
if (isInParole() != oldParoleState) {
postParoleStateChanged();
}
@@ -489,6 +502,11 @@ public class AppStandbyController implements AppStandbyInternal {
mInjector.onBootPhase(phase);
if (phase == PHASE_SYSTEM_SERVICES_READY) {
Slog.d(TAG, "Setting app idle enabled state");
+
+ if (mAppIdleEnabled) {
+ LocalServices.getService(UsageStatsManagerInternal.class).registerListener(this);
+ }
+
// Observe changes to the threshold
ConstantsObserver settingsObserver = new ConstantsObserver(mHandler);
settingsObserver.start();
@@ -912,8 +930,10 @@ public class AppStandbyController implements AppStandbyInternal {
}
}
- @Override
- public void reportEvent(UsageEvents.Event event, int userId) {
+ /**
+ * Callback to inform listeners of a new event.
+ */
+ public void onUsageEvent(int userId, @NonNull UsageEvents.Event event) {
if (!mAppIdleEnabled) return;
final int eventType = event.getEventType();
if ((eventType == UsageEvents.Event.ACTIVITY_RESUMED
diff --git a/cmds/statsd/src/OWNERS b/cmds/statsd/src/OWNERS
new file mode 100644
index 000000000000..0f3ddf7388d9
--- /dev/null
+++ b/cmds/statsd/src/OWNERS
@@ -0,0 +1,6 @@
+# Temporary OWNERS Block to assist with migration
+# bug: 167962588
+per-file *atoms.proto = set noparent
+per-file *atom_field_options.proto = set noparent
+per-file *atoms.proto = baligh@google.com, yro@google.com, singhtejinder@google.com, jeffreyhuang@google.com
+per-file *atom_field_options.proto = baligh@google.com, yro@google.com, singhtejinder@google.com, jeffreyhuang@google.com
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 0b044bee9e64..7d82f43af975 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -228,6 +228,7 @@ package android {
field public static final String SHOW_KEYGUARD_MESSAGE = "android.permission.SHOW_KEYGUARD_MESSAGE";
field public static final String SHUTDOWN = "android.permission.SHUTDOWN";
field public static final String START_ACTIVITIES_FROM_BACKGROUND = "android.permission.START_ACTIVITIES_FROM_BACKGROUND";
+ field public static final String START_FOREGROUND_SERVICES_FROM_BACKGROUND = "android.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND";
field public static final String STATUS_BAR_SERVICE = "android.permission.STATUS_BAR_SERVICE";
field public static final String STOP_APP_SWITCHES = "android.permission.STOP_APP_SWITCHES";
field public static final String SUBSTITUTE_NOTIFICATION_APP_NAME = "android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME";
@@ -603,7 +604,7 @@ package android.app {
method public static android.app.BroadcastOptions makeBasic();
method @RequiresPermission(android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND) public void setBackgroundActivityStartsAllowed(boolean);
method public void setDontSendToRestrictedApps(boolean);
- method @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public void setTemporaryAppWhitelistDuration(long);
+ method @RequiresPermission(anyOf={android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST, android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND, android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND}) public void setTemporaryAppWhitelistDuration(long);
method public android.os.Bundle toBundle();
}
@@ -1764,6 +1765,7 @@ package android.content {
field public static final String BACKUP_SERVICE = "backup";
field public static final String BATTERY_STATS_SERVICE = "batterystats";
field public static final int BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS = 1048576; // 0x100000
+ field public static final int BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND = 262144; // 0x40000
field public static final String BUGREPORT_SERVICE = "bugreport";
field public static final String CONTENT_SUGGESTIONS_SERVICE = "content_suggestions";
field public static final String CONTEXTHUB_SERVICE = "contexthub";
@@ -2280,6 +2282,7 @@ package android.content.pm {
field public static final int PROTECTION_FLAG_DOCUMENTER = 262144; // 0x40000
field public static final int PROTECTION_FLAG_INCIDENT_REPORT_APPROVER = 1048576; // 0x100000
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 public static final int PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER = 65536; // 0x10000
field public static final int PROTECTION_FLAG_WELLBEING = 131072; // 0x20000
diff --git a/core/java/android/app/BroadcastOptions.java b/core/java/android/app/BroadcastOptions.java
index 03dca30f8560..298c45582174 100644
--- a/core/java/android/app/BroadcastOptions.java
+++ b/core/java/android/app/BroadcastOptions.java
@@ -90,7 +90,9 @@ public class BroadcastOptions {
* power allowlist when this broadcast is being delivered to it.
* @param duration The duration in milliseconds; 0 means to not place on allowlist.
*/
- @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST)
+ @RequiresPermission(anyOf = {android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST,
+ android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND,
+ android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND})
public void setTemporaryAppWhitelistDuration(long duration) {
mTemporaryAppWhitelistDuration = duration;
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 2bf5368b691b..a886beddf64c 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -4901,7 +4901,7 @@ public class Notification implements Parcelable
bindNotificationHeader(contentView, p);
bindLargeIconAndApplyMargin(contentView, p, result);
boolean showProgress = handleProgressBar(contentView, ex, p);
- if (p.title != null && p.title.length() > 0 && !p.mHasCustomContent) {
+ if (p.hasTitle()) {
contentView.setViewVisibility(R.id.title, View.VISIBLE);
contentView.setTextViewText(R.id.title, processTextSpans(p.title));
setTextViewColorPrimary(contentView, R.id.title, p);
@@ -4909,7 +4909,7 @@ public class Notification implements Parcelable
? ViewGroup.LayoutParams.WRAP_CONTENT
: ViewGroup.LayoutParams.MATCH_PARENT);
}
- if (p.text != null) {
+ if (p.text != null && p.text.length() != 0) {
int textId = showProgress ? com.android.internal.R.id.text_line_1
: com.android.internal.R.id.text;
contentView.setTextViewText(textId, processTextSpans(p.text));
@@ -5296,7 +5296,7 @@ public class Notification implements Parcelable
contentView.setViewVisibility(R.id.app_name_text, View.GONE);
return false;
}
- if (p.mHeaderless && !p.mHasCustomContent) {
+ if (p.mHeaderless && p.hasTitle()) {
contentView.setViewVisibility(R.id.app_name_text, View.GONE);
// the headerless template will have the TITLE in this position; return true to
// keep the divider visible between that title and the next text element.
@@ -11073,6 +11073,10 @@ public class Notification implements Parcelable
return this;
}
+ final boolean hasTitle() {
+ return title != null && title.length() != 0 && !mHasCustomContent;
+ }
+
final StandardTemplateParams viewType(int viewType) {
mViewType = viewType;
return this;
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index b96b54ad8d21..3798de921dc7 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -697,6 +697,10 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac
* service element of manifest file. The value of attribute
* {@link android.R.attr#foregroundServiceType} can be multiple flags ORed together.</p>
*
+ * @throws IllegalStateException If the app targeting API is
+ * {@link android.os.Build.VERSION_CODES#S} or later, and the service is restricted from
+ * becoming foreground service due to background restriction.
+ *
* @param id The identifier for this notification as per
* {@link NotificationManager#notify(int, Notification)
* NotificationManager.notify(int, Notification)}; must not be 0.
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 16ae081049ef..56a95921091d 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -8505,6 +8505,8 @@ public class DevicePolicyManager {
* it previously set with {@link #addUserRestriction(ComponentName, String)}.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @return a {@link Bundle} whose keys are the user restrictions, and the values a
+ * {@code boolean} indicating whether the restriction is set.
* @throws SecurityException if {@code admin} is not a device or profile owner.
*/
public @NonNull Bundle getUserRestrictions(@NonNull ComponentName admin) {
diff --git a/core/java/android/bluetooth/BluetoothCodecStatus.java b/core/java/android/bluetooth/BluetoothCodecStatus.java
index 3a65aaa0d16c..7764ebeb2e33 100644
--- a/core/java/android/bluetooth/BluetoothCodecStatus.java
+++ b/core/java/android/bluetooth/BluetoothCodecStatus.java
@@ -18,7 +18,6 @@ package android.bluetooth;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
-import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -40,7 +39,7 @@ public final class BluetoothCodecStatus implements Parcelable {
* This extra represents the current codec status of the A2DP
* profile.
*/
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @UnsupportedAppUsage
public static final String EXTRA_CODEC_STATUS =
"android.bluetooth.extra.CODEC_STATUS";
@@ -199,7 +198,7 @@ public final class BluetoothCodecStatus implements Parcelable {
*
* @return the current codec configuration
*/
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @UnsupportedAppUsage
public @Nullable BluetoothCodecConfig getCodecConfig() {
return mCodecConfig;
}
@@ -209,7 +208,7 @@ public final class BluetoothCodecStatus implements Parcelable {
*
* @return an array with the codecs local capabilities
*/
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @UnsupportedAppUsage
public @Nullable BluetoothCodecConfig[] getCodecsLocalCapabilities() {
return mCodecsLocalCapabilities;
}
@@ -219,7 +218,7 @@ public final class BluetoothCodecStatus implements Parcelable {
*
* @return an array with the codecs selectable capabilities
*/
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @UnsupportedAppUsage
public @Nullable BluetoothCodecConfig[] getCodecsSelectableCapabilities() {
return mCodecsSelectableCapabilities;
}
diff --git a/core/java/android/companion/OWNERS b/core/java/android/companion/OWNERS
new file mode 100644
index 000000000000..da723b3b67da
--- /dev/null
+++ b/core/java/android/companion/OWNERS
@@ -0,0 +1 @@
+eugenesusla@google.com \ No newline at end of file
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 6a3f6b4034ff..8f92bf1e3253 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -367,6 +367,16 @@ public abstract class Context {
/*********** Hidden flags below this line ***********/
/**
+ * Flag for {@link #bindService}: allow background foreground service starts from the bound
+ * service's process.
+ * This flag is only respected if the caller is holding
+ * {@link android.Manifest.permission#START_FOREGROUND_SERVICES_FROM_BACKGROUND}.
+ * @hide
+ */
+ @SystemApi
+ public static final int BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND = 0x00040000;
+
+ /**
* Flag for {@link #bindService}: This flag is intended to be used only by the system to adjust
* the scheduling policy for IMEs (and any other out-of-process user-visible components that
* work closely with the top app) so that UI hosted in such services can have the same
@@ -3107,6 +3117,10 @@ public abstract class Context {
* @throws SecurityException If the caller does not have permission to access the service
* or the service can not be found.
*
+ * @throws IllegalStateException If the caller app's targeting API is
+ * {@link android.os.Build.VERSION_CODES#S} or later, and the foreground service is restricted
+ * from start due to background restriction.
+ *
* @see #stopService
* @see android.app.Service#startForeground(int, android.app.Notification)
*/
diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java
index c6450ffdf91c..cd9ba6a5b451 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -251,6 +251,16 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable {
@SystemApi
public static final int PROTECTION_FLAG_RETAIL_DEMO = 0x1000000;
+ /**
+ * Additional flag for {@link #protectionLevel}, corresponding
+ * to the <code>recents</code> value of
+ * {@link android.R.attr#protectionLevel}.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int PROTECTION_FLAG_RECENTS = 0x2000000;
+
/** @hide */
@IntDef(flag = true, prefix = { "PROTECTION_FLAG_" }, value = {
PROTECTION_FLAG_PRIVILEGED,
@@ -274,6 +284,7 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable {
PROTECTION_FLAG_APP_PREDICTOR,
PROTECTION_FLAG_COMPANION,
PROTECTION_FLAG_RETAIL_DEMO,
+ PROTECTION_FLAG_RECENTS,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ProtectionFlags {}
@@ -532,6 +543,9 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable {
if ((level & PermissionInfo.PROTECTION_FLAG_RETAIL_DEMO) != 0) {
protLevel.append("|retailDemo");
}
+ if ((level & PermissionInfo.PROTECTION_FLAG_RECENTS) != 0) {
+ protLevel.append("|recents");
+ }
return protLevel.toString();
}
diff --git a/core/java/android/hardware/biometrics/SensorPropertiesInternal.java b/core/java/android/hardware/biometrics/SensorPropertiesInternal.java
index 2189de0827b7..0b81c6c8cc25 100644
--- a/core/java/android/hardware/biometrics/SensorPropertiesInternal.java
+++ b/core/java/android/hardware/biometrics/SensorPropertiesInternal.java
@@ -16,13 +16,10 @@
package android.hardware.biometrics;
-import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
/**
* The base class containing all modality-agnostic information. This is a superset of the
* {@link android.hardware.biometrics.common.CommonProps}, and provides backwards-compatible
@@ -35,6 +32,11 @@ public class SensorPropertiesInternal implements Parcelable {
@SensorProperties.Strength public final int sensorStrength;
public final int maxEnrollmentsPerUser;
+ public static SensorPropertiesInternal from(@NonNull SensorPropertiesInternal prop) {
+ return new SensorPropertiesInternal(prop.sensorId, prop.sensorStrength,
+ prop.maxEnrollmentsPerUser);
+ }
+
protected SensorPropertiesInternal(int sensorId, @SensorProperties.Strength int sensorStrength,
int maxEnrollmentsPerUser) {
this.sensorId = sensorId;
@@ -72,4 +74,10 @@ public class SensorPropertiesInternal implements Parcelable {
dest.writeInt(sensorStrength);
dest.writeInt(maxEnrollmentsPerUser);
}
+
+ @Override
+ public String toString() {
+ return "ID: " + sensorId + ", Strength: " + sensorStrength
+ + ", MaxEnrollmentsPerUser: " + maxEnrollmentsPerUser;
+ }
}
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index b046d1df5b8c..7b4889f0a1b3 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -358,7 +358,7 @@ public final class DisplayManagerGlobal {
// listener.
DisplayInfo display = getDisplayInfoLocked(displayId);
if (display != null) {
- float refreshRate = display.getMode().getRefreshRate();
+ float refreshRate = display.getRefreshRate();
// Signal native callbacks if we ever set a refresh rate.
nSignalNativeCallbacks(refreshRate);
}
@@ -862,7 +862,7 @@ public final class DisplayManagerGlobal {
if (display != null) {
// We need to tell AChoreographer instances the current refresh rate so that apps
// can get it for free once a callback first registers.
- float refreshRate = display.getMode().getRefreshRate();
+ float refreshRate = display.getRefreshRate();
nSignalNativeCallbacks(refreshRate);
}
}
diff --git a/core/java/android/hardware/face/FaceSensorPropertiesInternal.java b/core/java/android/hardware/face/FaceSensorPropertiesInternal.java
index e91554b532b0..b9c0d12de22b 100644
--- a/core/java/android/hardware/face/FaceSensorPropertiesInternal.java
+++ b/core/java/android/hardware/face/FaceSensorPropertiesInternal.java
@@ -19,7 +19,6 @@ package android.hardware.face;
import android.hardware.biometrics.SensorProperties;
import android.hardware.biometrics.SensorPropertiesInternal;
import android.os.Parcel;
-import android.os.Parcelable;
/**
* Container for face sensor properties.
@@ -78,4 +77,9 @@ public class FaceSensorPropertiesInternal extends SensorPropertiesInternal {
dest.writeBoolean(supportsFaceDetection);
dest.writeBoolean(supportsSelfIllumination);
}
+
+ @Override
+ public String toString() {
+ return "ID: " + sensorId + ", Strength: " + sensorStrength;
+ }
}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 00023a5caf75..9c2ae4e7c48a 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -2481,6 +2481,29 @@ public abstract class BatteryStats implements Parcelable {
"group", "compl", "dorm", "uninit"
};
+ /**
+ * Returned value if energy data is unavailable
+ *
+ * {@hide}
+ */
+ public static final long ENERGY_DATA_UNAVAILABLE = -1;
+
+ /**
+ * Returns the energy in microjoules that the screen consumed while on.
+ * Will return {@link #ENERGY_DATA_UNAVAILABLE} if data is unavailable
+ *
+ * {@hide}
+ */
+ public abstract long getScreenOnEnergy();
+
+ /**
+ * Returns the energy in microjoules that the screen consumed while in doze
+ * Will return {@link #ENERGY_DATA_UNAVAILABLE} if data is unavailable
+ *
+ * {@hide}
+ */
+ public abstract long getScreenDozeEnergy();
+
public static final BitDescription[] HISTORY_STATE_DESCRIPTIONS = new BitDescription[] {
new BitDescription(HistoryItem.STATE_CPU_RUNNING_FLAG, "running", "r"),
new BitDescription(HistoryItem.STATE_WAKE_LOCK_FLAG, "wake_lock", "w"),
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
index e32ffa6e9d05..18921639f55d 100644
--- a/core/java/android/security/keymaster/KeymasterDefs.java
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -94,6 +94,8 @@ public final class KeymasterDefs {
public static final int KM_TAG_ATTESTATION_ID_MEID = KM_BYTES | 715;
public static final int KM_TAG_ATTESTATION_ID_MANUFACTURER = KM_BYTES | 716;
public static final int KM_TAG_ATTESTATION_ID_MODEL = KM_BYTES | 717;
+ public static final int KM_TAG_VENDOR_PATCHLEVEL = KM_UINT | 718;
+ public static final int KM_TAG_BOOT_PATCHLEVEL = KM_UINT | 719;
public static final int KM_TAG_DEVICE_UNIQUE_ATTESTATION = KM_BOOL | 720;
public static final int KM_TAG_ASSOCIATED_DATA = KM_BYTES | 1000;
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index 3da3184afae1..59299f6b15eb 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -276,7 +276,7 @@ public final class Choreographer {
private static float getRefreshRate() {
DisplayInfo di = DisplayManagerGlobal.getInstance().getDisplayInfo(
Display.DEFAULT_DISPLAY);
- return di.getMode().getRefreshRate();
+ return di.getRefreshRate();
}
/**
@@ -944,7 +944,7 @@ public final class Choreographer {
private VsyncEventData mLastVsyncEventData = new VsyncEventData();
public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
- super(looper, vsyncSource, CONFIG_CHANGED_EVENT_SUPPRESS);
+ super(looper, vsyncSource, 0);
}
// TODO(b/116025192): physicalDisplayId is ignored because SF only emits VSYNC events for
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 3021aa6a0783..56c7e27151e0 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -456,6 +456,9 @@ public final class Display {
// TODO (b/114338689): Remove the flag and use WindowManager#REMOVE_CONTENT_MODE_DESTROY
public static final int REMOVE_MODE_DESTROY_CONTENT = 1;
+ /** @hide */
+ public static final int DISPLAY_MODE_ID_FOR_FRAME_RATE_OVERRIDE = 0xFF;
+
/**
* Internal method to create a display.
* The display created with this method will have a static {@link DisplayAdjustments} applied.
@@ -886,7 +889,7 @@ public final class Display {
public float getRefreshRate() {
synchronized (this) {
updateDisplayInfoLocked();
- return mDisplayInfo.getMode().getRefreshRate();
+ return mDisplayInfo.getRefreshRate();
}
}
@@ -1391,6 +1394,23 @@ public final class Display {
}
/**
+ * Returns true if the display is in an off state such as {@link #STATE_OFF}.
+ * @hide
+ */
+ public static boolean isOffState(int state) {
+ return state == STATE_OFF;
+ }
+
+ /**
+ * Returns true if the display is in an on state such as {@link #STATE_ON}
+ * or {@link #STATE_VR} or {@link #STATE_ON_SUSPEND}.
+ * @hide
+ */
+ public static boolean isOnState(int state) {
+ return state == STATE_ON || state == STATE_VR || state == STATE_ON_SUSPEND;
+ }
+
+ /**
* A mode supported by a given display.
*
* @see Display#getSupportedModes()
@@ -1509,6 +1529,16 @@ public final class Display {
Float.floatToIntBits(mRefreshRate) == Float.floatToIntBits(refreshRate);
}
+ /**
+ * Returns {@code true} if this mode equals to the other mode in all parameters except
+ * the refresh rate.
+ *
+ * @hide
+ */
+ public boolean equalsExceptRefreshRate(@Nullable Display.Mode other) {
+ return mWidth == other.mWidth && mHeight == other.mHeight;
+ }
+
@Override
public boolean equals(@Nullable Object other) {
if (this == other) {
diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java
index e8a4ed44b7c8..5d4a4e52975a 100644
--- a/core/java/android/view/DisplayEventReceiver.java
+++ b/core/java/android/view/DisplayEventReceiver.java
@@ -23,6 +23,8 @@ import android.os.Looper;
import android.os.MessageQueue;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
+
import dalvik.annotation.optimization.FastNative;
import dalvik.system.CloseGuard;
@@ -56,18 +58,18 @@ public abstract class DisplayEventReceiver {
public static final int VSYNC_SOURCE_SURFACE_FLINGER = 1;
/**
- * Specifies to suppress config changed events from being generated from Surface Flinger.
+ * Specifies to generate config changed events from Surface Flinger.
* <p>
* Needs to be kept in sync with frameworks/native/include/gui/ISurfaceComposer.h
*/
- public static final int CONFIG_CHANGED_EVENT_SUPPRESS = 0;
+ public static final int EVENT_REGISTRATION_CONFIG_CHANGED_FLAG = 0x1;
/**
- * Specifies to generate config changed events from Surface Flinger.
+ * Specifies to generate frame rate override events from Surface Flinger.
* <p>
* Needs to be kept in sync with frameworks/native/include/gui/ISurfaceComposer.h
*/
- public static final int CONFIG_CHANGED_EVENT_DISPATCH = 1;
+ public static final int EVENT_REGISTRATION_FRAME_RATE_OVERRIDE_FLAG = 0x2;
private static final String TAG = "DisplayEventReceiver";
@@ -81,7 +83,7 @@ public abstract class DisplayEventReceiver {
private MessageQueue mMessageQueue;
private static native long nativeInit(WeakReference<DisplayEventReceiver> receiver,
- MessageQueue messageQueue, int vsyncSource, int configChanged);
+ MessageQueue messageQueue, int vsyncSource, int eventRegistration);
private static native void nativeDispose(long receiverPtr);
@FastNative
private static native void nativeScheduleVsync(long receiverPtr);
@@ -93,7 +95,7 @@ public abstract class DisplayEventReceiver {
*/
@UnsupportedAppUsage
public DisplayEventReceiver(Looper looper) {
- this(looper, VSYNC_SOURCE_APP, CONFIG_CHANGED_EVENT_SUPPRESS);
+ this(looper, VSYNC_SOURCE_APP, 0);
}
/**
@@ -101,17 +103,17 @@ public abstract class DisplayEventReceiver {
*
* @param looper The looper to use when invoking callbacks.
* @param vsyncSource The source of the vsync tick. Must be on of the VSYNC_SOURCE_* values.
- * @param configChanged Whether to dispatch config changed events. Must be one of the
- * CONFIG_CHANGED_EVENT_* values.
+ * @param eventRegistration Which events to dispatch. Must be a bitfield consist of the
+ * EVENT_REGISTRATION_*_FLAG values.
*/
- public DisplayEventReceiver(Looper looper, int vsyncSource, int configChanged) {
+ public DisplayEventReceiver(Looper looper, int vsyncSource, int eventRegistration) {
if (looper == null) {
throw new IllegalArgumentException("looper must not be null");
}
mMessageQueue = looper.getQueue();
mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), mMessageQueue,
- vsyncSource, configChanged);
+ vsyncSource, eventRegistration);
mCloseGuard.open("dispose");
}
@@ -206,6 +208,41 @@ public abstract class DisplayEventReceiver {
}
/**
+ * Represents a mapping between a UID and an override frame rate
+ */
+ public static class FrameRateOverride {
+ // The application uid
+ public final int uid;
+
+ // The frame rate that this application runs at
+ public final float frameRateHz;
+
+
+ @VisibleForTesting
+ public FrameRateOverride(int uid, float frameRateHz) {
+ this.uid = uid;
+ this.frameRateHz = frameRateHz;
+ }
+
+ @Override
+ public String toString() {
+ return "{uid=" + uid + " frameRateHz=" + frameRateHz + "}";
+ }
+ }
+
+ /**
+ * Called when frame rate override event is received.
+ *
+ * @param timestampNanos The timestamp of the event, in the {@link System#nanoTime()}
+ * timebase.
+ * @param physicalDisplayId Stable display ID that uniquely describes a (display, port) pair.
+ * @param overrides The mappings from uid to frame rates
+ */
+ public void onFrameRateOverridesChanged(long timestampNanos, long physicalDisplayId,
+ FrameRateOverride[] overrides) {
+ }
+
+ /**
* Schedules a single vertical sync pulse to be delivered when the next
* display frame begins.
*/
@@ -240,4 +277,11 @@ public abstract class DisplayEventReceiver {
onConfigChanged(timestampNanos, physicalDisplayId, configId);
}
+ // Called from native code.
+ @SuppressWarnings("unused")
+ private void dispatchFrameRateOverrides(long timestampNanos, long physicalDisplayId,
+ FrameRateOverride[] overrides) {
+ onFrameRateOverridesChanged(timestampNanos, physicalDisplayId, overrides);
+ }
+
}
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index fe9a1a76bbaf..020160584f67 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -261,6 +261,11 @@ public final class DisplayInfo implements Parcelable {
public String ownerPackageName;
/**
+ * The refresh rate override for this app. 0 means no override.
+ */
+ public float refreshRateOverride;
+
+ /**
* @hide
* Get current remove mode of the display - what actions should be performed with the display's
* content when it is removed.
@@ -332,7 +337,8 @@ public final class DisplayInfo implements Parcelable {
&& state == other.state
&& ownerUid == other.ownerUid
&& Objects.equals(ownerPackageName, other.ownerPackageName)
- && removeMode == other.removeMode;
+ && removeMode == other.removeMode
+ && refreshRateOverride == other.refreshRateOverride;
}
@Override
@@ -376,6 +382,7 @@ public final class DisplayInfo implements Parcelable {
ownerUid = other.ownerUid;
ownerPackageName = other.ownerPackageName;
removeMode = other.removeMode;
+ refreshRateOverride = other.refreshRateOverride;
}
public void readFromParcel(Parcel source) {
@@ -421,6 +428,7 @@ public final class DisplayInfo implements Parcelable {
ownerPackageName = source.readString8();
uniqueId = source.readString8();
removeMode = source.readInt();
+ refreshRateOverride = source.readFloat();
}
@Override
@@ -465,6 +473,7 @@ public final class DisplayInfo implements Parcelable {
dest.writeString8(ownerPackageName);
dest.writeString8(uniqueId);
dest.writeInt(removeMode);
+ dest.writeFloat(refreshRateOverride);
}
@Override
@@ -472,6 +481,17 @@ public final class DisplayInfo implements Parcelable {
return 0;
}
+ /**
+ * Returns the refresh rate the application would experience.
+ */
+ public float getRefreshRate() {
+ if (refreshRateOverride > 0) {
+ return refreshRateOverride;
+ }
+
+ return getMode().getRefreshRate();
+ }
+
public Display.Mode getMode() {
return findMode(modeId);
}
@@ -675,6 +695,9 @@ public final class DisplayInfo implements Parcelable {
}
sb.append(", removeMode ");
sb.append(removeMode);
+ sb.append(", refreshRateOverride ");
+ sb.append(refreshRateOverride);
+
sb.append("}");
return sb.toString();
}
diff --git a/core/java/android/webkit/PacProcessor.java b/core/java/android/webkit/PacProcessor.java
index d7b4e8bba884..21fa6fc88c13 100644
--- a/core/java/android/webkit/PacProcessor.java
+++ b/core/java/android/webkit/PacProcessor.java
@@ -54,7 +54,7 @@ public interface PacProcessor {
*/
@NonNull
static PacProcessor createInstance() {
- throw new UnsupportedOperationException("Not implemented");
+ return WebViewFactory.getProvider().createPacProcessor();
}
/**
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index e74ce53306c1..a034a7c2dc7e 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -156,7 +156,8 @@ public final class SelectionActionModeHelper {
mSmartSelectSprite != null
? this::startSelectionActionModeWithSmartSelectAnimation
: this::startSelectionActionMode,
- mTextClassificationHelper::getOriginalSelection)
+ mTextClassificationHelper::getOriginalSelection,
+ mTextClassificationHelper::isTextClassifierDestroyed)
.execute();
}
}
@@ -178,7 +179,8 @@ public final class SelectionActionModeHelper {
mTextClassificationHelper.getTimeoutDuration(),
mTextClassificationHelper::classifyText,
this::startLinkActionMode,
- mTextClassificationHelper::getOriginalSelection)
+ mTextClassificationHelper::getOriginalSelection,
+ mTextClassificationHelper::isTextClassifierDestroyed)
.execute();
}
}
@@ -194,7 +196,8 @@ public final class SelectionActionModeHelper {
mTextClassificationHelper.getTimeoutDuration(),
mTextClassificationHelper::classifyText,
this::invalidateActionMode,
- mTextClassificationHelper::getOriginalSelection)
+ mTextClassificationHelper::getOriginalSelection,
+ mTextClassificationHelper::isTextClassifierDestroyed)
.execute();
}
}
@@ -992,6 +995,7 @@ public final class SelectionActionModeHelper {
private final Supplier<SelectionResult> mSelectionResultSupplier;
private final Consumer<SelectionResult> mSelectionResultCallback;
private final Supplier<SelectionResult> mTimeOutResultSupplier;
+ private final Supplier<Boolean> mIsTextClassifierDestroyedSupplier;
private final TextView mTextView;
private final String mOriginalText;
@@ -1006,13 +1010,16 @@ public final class SelectionActionModeHelper {
@NonNull TextView textView, int timeOut,
@NonNull Supplier<SelectionResult> selectionResultSupplier,
@NonNull Consumer<SelectionResult> selectionResultCallback,
- @NonNull Supplier<SelectionResult> timeOutResultSupplier) {
+ @NonNull Supplier<SelectionResult> timeOutResultSupplier,
+ @NonNull Supplier<Boolean> isTextClassifierDestroyedSupplier) {
super(textView != null ? textView.getHandler() : null);
mTextView = Objects.requireNonNull(textView);
mTimeOutDuration = timeOut;
mSelectionResultSupplier = Objects.requireNonNull(selectionResultSupplier);
mSelectionResultCallback = Objects.requireNonNull(selectionResultCallback);
mTimeOutResultSupplier = Objects.requireNonNull(timeOutResultSupplier);
+ mIsTextClassifierDestroyedSupplier =
+ Objects.requireNonNull(isTextClassifierDestroyedSupplier);
// Make a copy of the original text.
mOriginalText = getText(mTextView).toString();
}
@@ -1022,7 +1029,19 @@ public final class SelectionActionModeHelper {
protected SelectionResult doInBackground(Void... params) {
final Runnable onTimeOut = this::onTimeOut;
mTextView.postDelayed(onTimeOut, mTimeOutDuration);
- final SelectionResult result = mSelectionResultSupplier.get();
+ SelectionResult result = null;
+ try {
+ result = mSelectionResultSupplier.get();
+ } catch (IllegalStateException e) {
+ // Swallows the exception if the text classifier session is destroyed
+ if (mIsTextClassifierDestroyedSupplier.get()) {
+ Log.w(LOG_TAG,
+ "TextClassificationAsyncTask failed because TextClassifier destroyed",
+ e);
+ } else {
+ throw e;
+ }
+ }
mTextView.removeCallbacks(onTimeOut);
return result;
}
@@ -1154,6 +1173,10 @@ public final class SelectionActionModeHelper {
}
}
+ public boolean isTextClassifierDestroyed() {
+ return mTextClassifier.get().isDestroyed();
+ }
+
private boolean isDarkLaunchEnabled() {
return TextClassificationManager.getSettings(mContext).isModelDarkLaunchEnabled();
}
diff --git a/core/java/android/window/DisplayAreaOrganizer.java b/core/java/android/window/DisplayAreaOrganizer.java
index 6e20452ad061..1ac188cf2486 100644
--- a/core/java/android/window/DisplayAreaOrganizer.java
+++ b/core/java/android/window/DisplayAreaOrganizer.java
@@ -101,6 +101,19 @@ public class DisplayAreaOrganizer extends WindowOrganizer {
public static final int FEATURE_VENDOR_FIRST = FEATURE_SYSTEM_LAST + 1;
/**
+ * Last possible vendor specific display area id.
+ * @hide
+ */
+ public static final int FEATURE_VENDOR_LAST = FEATURE_VENDOR_FIRST + 10_000;
+
+ /**
+ * Task display areas that can be created at runtime start with this value.
+ * @see #createTaskDisplayArea(int, int, String)
+ * @hide
+ */
+ public static final int FEATURE_RUNTIME_TASK_CONTAINER_FIRST = FEATURE_VENDOR_LAST + 1;
+
+ /**
* Registers a DisplayAreaOrganizer to manage display areas for a given feature. A feature can
* not be registered by multiple organizers at the same time.
*
@@ -132,6 +145,50 @@ public class DisplayAreaOrganizer extends WindowOrganizer {
}
/**
+ * Creates a persistent task display area. It will be added to be the top most task display area
+ * in the root.
+ *
+ * The new created TDA is organized by the organizer, and will be deleted on calling
+ * {@link #deleteTaskDisplayArea(WindowContainerToken)} or {@link #unregisterOrganizer()}.
+ *
+ * @param displayId the display to create the new task display area in.
+ * @param rootFeatureId the root display area to create the new task display area in. Caller can
+ * use {@link #FEATURE_ROOT} as the root of the logical display.
+ * @param name the name for the new task display area.
+ * @return the new created task display area.
+ * @throws IllegalArgumentException if failed to create a new task display area.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
+ @CallSuper
+ @NonNull
+ public DisplayAreaAppearedInfo createTaskDisplayArea(int displayId, int rootFeatureId,
+ @NonNull String name) {
+ try {
+ return getController().createTaskDisplayArea(
+ mInterface, displayId, rootFeatureId, name);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Deletes a persistent task display area. It can only be one that created by an organizer.
+ *
+ * @throws IllegalArgumentException if failed to delete the task display area.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
+ @CallSuper
+ public void deleteTaskDisplayArea(@NonNull WindowContainerToken taskDisplayArea) {
+ try {
+ getController().deleteTaskDisplayArea(taskDisplayArea);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Called when a DisplayArea of the registered window type can be controlled by this organizer.
* It will not be called for the DisplayAreas that exist when {@link #registerOrganizer(int)} is
* called.
diff --git a/core/java/android/window/IDisplayAreaOrganizerController.aidl b/core/java/android/window/IDisplayAreaOrganizerController.aidl
index edabcf8ad0de..26fa434506cf 100644
--- a/core/java/android/window/IDisplayAreaOrganizerController.aidl
+++ b/core/java/android/window/IDisplayAreaOrganizerController.aidl
@@ -19,6 +19,7 @@ package android.window;
import android.content.pm.ParceledListSlice;
import android.window.DisplayAreaAppearedInfo;
import android.window.IDisplayAreaOrganizer;
+import android.window.WindowContainerToken;
/** @hide */
interface IDisplayAreaOrganizerController {
@@ -37,4 +38,28 @@ interface IDisplayAreaOrganizerController {
* Unregisters a previously registered display area organizer.
*/
void unregisterOrganizer(in IDisplayAreaOrganizer organizer);
+
+ /**
+ * Creates a persistent task display area. It will be added to be the top most task display area
+ * in the root.
+ *
+ * The new created TDA is organized by the organizer, and will be deleted on calling
+ * {@link #deleteTaskDisplayArea(WindowContainerToken)} or {@link #unregisterOrganizer()}.
+ *
+ * @param displayId the display to create the new task display area in.
+ * @param rootFeatureId the root display area to create the new task display area in. Caller can
+ * use {@link #FEATURE_ROOT} as the root of the logical display.
+ * @param name the name for the new task display area.
+ * @return the new created task display area.
+ * @throws IllegalArgumentException if failed to create a new task display area.
+ */
+ DisplayAreaAppearedInfo createTaskDisplayArea(in IDisplayAreaOrganizer organizer, int displayId,
+ int rootFeatureId, in String name);
+
+ /**
+ * Deletes a persistent task display area. It can only be one that created by an organizer.
+ *
+ * @throws IllegalArgumentException if failed to delete the task display area.
+ */
+ void deleteTaskDisplayArea(in WindowContainerToken taskDisplayArea);
}
diff --git a/core/java/com/android/internal/content/FileSystemProvider.java b/core/java/com/android/internal/content/FileSystemProvider.java
index 3b5fecfc600a..0ede1b86b524 100644
--- a/core/java/com/android/internal/content/FileSystemProvider.java
+++ b/core/java/com/android/internal/content/FileSystemProvider.java
@@ -20,15 +20,14 @@ import android.annotation.CallSuper;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ContentResolver;
+import android.content.Context;
import android.content.Intent;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
-import android.database.DatabaseUtils;
import android.database.MatrixCursor;
import android.database.MatrixCursor.RowBuilder;
import android.graphics.Point;
import android.net.Uri;
-import android.os.Binder;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.FileObserver;
@@ -39,7 +38,6 @@ import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
import android.provider.DocumentsProvider;
import android.provider.MediaStore;
-import android.provider.MediaStore.Files.FileColumns;
import android.provider.MetadataReader;
import android.system.Int64Ref;
import android.text.TextUtils;
@@ -66,6 +64,7 @@ import java.nio.file.attribute.BasicFileAttributes;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
+import java.util.Locale;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Predicate;
@@ -271,8 +270,7 @@ public abstract class FileSystemProvider extends DocumentsProvider {
throw new IllegalStateException("Failed to touch " + file + ": " + e);
}
}
- MediaStore.scanFile(getContext().getContentResolver(), file);
-
+ updateMediaStore(getContext(), file);
return childId;
}
@@ -295,7 +293,9 @@ public abstract class FileSystemProvider extends DocumentsProvider {
onDocIdChanged(afterDocId);
final File afterVisibleFile = getFileForDocId(afterDocId, true);
- moveInMediaStore(beforeVisibleFile, afterVisibleFile);
+
+ updateMediaStore(getContext(), beforeVisibleFile);
+ updateMediaStore(getContext(), afterVisibleFile);
if (!TextUtils.equals(docId, afterDocId)) {
return afterDocId;
@@ -323,17 +323,23 @@ public abstract class FileSystemProvider extends DocumentsProvider {
onDocIdChanged(sourceDocumentId);
onDocIdDeleted(sourceDocumentId);
onDocIdChanged(docId);
- moveInMediaStore(visibleFileBefore, getFileForDocId(docId, true));
-
+ // update the database
+ updateMediaStore(getContext(), visibleFileBefore);
+ updateMediaStore(getContext(), getFileForDocId(docId, true));
return docId;
}
- private void moveInMediaStore(@Nullable File oldVisibleFile, @Nullable File newVisibleFile) {
- if (oldVisibleFile != null) {
- MediaStore.scanFile(getContext().getContentResolver(), oldVisibleFile);
- }
- if (newVisibleFile != null) {
- MediaStore.scanFile(getContext().getContentResolver(), newVisibleFile);
+ private static void updateMediaStore(@NonNull Context context, File file) {
+ if (file != null) {
+ final ContentResolver resolver = context.getContentResolver();
+ final String noMedia = ".nomedia";
+ // For file, check whether the file name is .nomedia or not.
+ // If yes, scan the parent directory to update all files in the directory.
+ if (!file.isDirectory() && file.getName().toLowerCase(Locale.ROOT).endsWith(noMedia)) {
+ MediaStore.scanFile(resolver, file.getParentFile());
+ } else {
+ MediaStore.scanFile(resolver, file);
+ }
}
}
@@ -354,35 +360,7 @@ public abstract class FileSystemProvider extends DocumentsProvider {
onDocIdChanged(docId);
onDocIdDeleted(docId);
- removeFromMediaStore(visibleFile);
- }
-
- private void removeFromMediaStore(@Nullable File visibleFile)
- throws FileNotFoundException {
- // visibleFolder is null if we're removing a document from external thumb drive or SD card.
- if (visibleFile != null) {
- final long token = Binder.clearCallingIdentity();
-
- try {
- final ContentResolver resolver = getContext().getContentResolver();
- final Uri externalUri = MediaStore.Files.getContentUri("external");
- final Bundle queryArgs = new Bundle();
- queryArgs.putInt(MediaStore.QUERY_ARG_MATCH_PENDING, MediaStore.MATCH_INCLUDE);
-
- // Remove the media store entry corresponding to visibleFile and if it is a
- // directory, also remove media store entries for any files inside this directory.
- // Logic borrowed from com.android.providers.media.scan.ModernMediaScanner.
- final String pathEscapedForLike = DatabaseUtils.escapeForLike(
- visibleFile.getAbsolutePath());
- ContentResolver.includeSqlSelectionArgs(queryArgs,
- FileColumns.DATA + " LIKE ? ESCAPE '\\' OR "
- + FileColumns.DATA + " LIKE ? ESCAPE '\\'",
- new String[] {pathEscapedForLike + "/%", pathEscapedForLike});
- resolver.delete(externalUri, queryArgs);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
+ updateMediaStore(getContext(), visibleFile);
}
@Override
diff --git a/core/java/com/android/internal/infra/AbstractMultiplePendingRequestsRemoteService.java b/core/java/com/android/internal/infra/AbstractMultiplePendingRequestsRemoteService.java
index 70505bc5895b..6c01780dac76 100644
--- a/core/java/com/android/internal/infra/AbstractMultiplePendingRequestsRemoteService.java
+++ b/core/java/com/android/internal/infra/AbstractMultiplePendingRequestsRemoteService.java
@@ -33,7 +33,10 @@ import java.util.List;
*
* @param <S> the concrete remote service class
* @param <I> the interface of the binder service
+ *
+ * @deprecated Use {@link ServiceConnector} to manage remote service connections
*/
+@Deprecated
public abstract class AbstractMultiplePendingRequestsRemoteService<S
extends AbstractMultiplePendingRequestsRemoteService<S, I>, I extends IInterface>
extends AbstractRemoteService<S, I> {
diff --git a/core/java/com/android/internal/infra/AbstractRemoteService.java b/core/java/com/android/internal/infra/AbstractRemoteService.java
index 722e5c102fcf..f63ac2e14e20 100644
--- a/core/java/com/android/internal/infra/AbstractRemoteService.java
+++ b/core/java/com/android/internal/infra/AbstractRemoteService.java
@@ -58,9 +58,12 @@ import java.util.ArrayList;
* @param <S> the concrete remote service class
* @param <I> the interface of the binder service
*
+ * @deprecated Use {@link ServiceConnector} to manage remote service connections
+ *
* @hide
*/
//TODO(b/117779333): improve javadoc above instead of using Autofill as an example
+@Deprecated
public abstract class AbstractRemoteService<S extends AbstractRemoteService<S, I>,
I extends IInterface> implements DeathRecipient {
private static final int MSG_BIND = 1;
diff --git a/core/java/com/android/internal/infra/AbstractSinglePendingRequestRemoteService.java b/core/java/com/android/internal/infra/AbstractSinglePendingRequestRemoteService.java
index 2ebf2fd820d8..0d9af8c8bcf5 100644
--- a/core/java/com/android/internal/infra/AbstractSinglePendingRequestRemoteService.java
+++ b/core/java/com/android/internal/infra/AbstractSinglePendingRequestRemoteService.java
@@ -33,8 +33,11 @@ import java.io.PrintWriter;
* @param <S> the concrete remote service class
* @param <I> the interface of the binder service
*
+ * @deprecated Use {@link ServiceConnector} to manage remote service connections
+ *
* @hide
*/
+@Deprecated
public abstract class AbstractSinglePendingRequestRemoteService<S
extends AbstractSinglePendingRequestRemoteService<S, I>, I extends IInterface>
extends AbstractRemoteService<S, I> {
diff --git a/core/java/com/android/internal/infra/OWNERS b/core/java/com/android/internal/infra/OWNERS
new file mode 100644
index 000000000000..45503582b2c5
--- /dev/null
+++ b/core/java/com/android/internal/infra/OWNERS
@@ -0,0 +1,6 @@
+per-file AndroidFuture.java = eugenesusla@google.com
+per-file RemoteStream.java = eugenesusla@google.com
+per-file PerUser.java = eugenesusla@google.com
+per-file ServiceConnector.java = eugenesusla@google.com
+per-file AndroidFuture.aidl = eugenesusla@google.com
+per-file IAndroidFuture.aidl = eugenesusla@google.com \ No newline at end of file
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 7c442b408624..7571f5db8cad 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -98,6 +98,8 @@ import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidActiveTimeRead
import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidClusterTimeReader;
import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidFreqTimeReader;
import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidUserSysTimeReader;
+import com.android.internal.power.MeasuredEnergyArray;
+import com.android.internal.power.MeasuredEnergyStats;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.FastXmlSerializer;
@@ -155,7 +157,7 @@ public class BatteryStatsImpl extends BatteryStats {
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- static final int VERSION = 189 + (USE_OLD_HISTORY ? 1000 : 0);
+ static final int VERSION = 190 + (USE_OLD_HISTORY ? 1000 : 0);
// The maximum number of names wakelocks we will keep track of
// per uid; once the limit is reached, we batch the remaining wakelocks
@@ -349,12 +351,20 @@ public class BatteryStatsImpl extends BatteryStats {
}
/** interface to update rail information for power monitor */
- public interface RailEnergyDataCallback {
+ public interface MeasuredEnergyRetriever {
/** Function to fill the map for the rail data stats
* Used for power monitoring feature
* @param railStats
*/
void fillRailDataStats(RailStats railStats);
+ /**
+ * Function to get energy consumption data
+ *
+ * @return an array of measured energy (in microjoules) since boot, will be null if
+ * measured energy data is unavailable
+ */
+ @Nullable
+ MeasuredEnergyArray getEnergyConsumptionData();
}
public static abstract class UserInfoProvider {
@@ -391,7 +401,7 @@ public class BatteryStatsImpl extends BatteryStats {
}
};
- public final RailEnergyDataCallback mRailEnergyDataCallback;
+ public final MeasuredEnergyRetriever mMeasuredEnergyRetriever;
/**
* This handler is running on {@link BackgroundThread}.
@@ -624,8 +634,10 @@ public class BatteryStatsImpl extends BatteryStats {
int UPDATE_WIFI = 0x02;
int UPDATE_RADIO = 0x04;
int UPDATE_BT = 0x08;
- int UPDATE_RPM = 0x10; // 16
- int UPDATE_ALL = UPDATE_CPU | UPDATE_WIFI | UPDATE_RADIO | UPDATE_BT | UPDATE_RPM;
+ int UPDATE_RPM = 0x10;
+ int UPDATE_ENERGY = 0x20;
+ int UPDATE_ALL =
+ UPDATE_CPU | UPDATE_WIFI | UPDATE_RADIO | UPDATE_BT | UPDATE_RPM | UPDATE_ENERGY;
Future<?> scheduleSync(String reason, int flags);
Future<?> scheduleCpuSyncDueToRemovedUid(int uid);
@@ -633,8 +645,11 @@ public class BatteryStatsImpl extends BatteryStats {
long delayMillis);
Future<?> scheduleCopyFromAllUidsCpuTimes(boolean onBattery, boolean onBatteryScreenOff);
Future<?> scheduleCpuSyncDueToSettingChange();
- Future<?> scheduleCpuSyncDueToScreenStateChange(boolean onBattery,
- boolean onBatteryScreenOff);
+ /**
+ * Schedule a sync because of a screen state change.
+ */
+ Future<?> scheduleSyncDueToScreenStateChange(int flags, boolean onBattery,
+ boolean onBatteryScreenOff, int screenState);
Future<?> scheduleCpuSyncDueToWakelockChange(long delayMillis);
void cancelCpuSyncDueToWakelockChange();
Future<?> scheduleSyncDueToBatteryLevelChange(long delayMillis);
@@ -932,6 +947,13 @@ public class BatteryStatsImpl extends BatteryStats {
int mWifiRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
/**
+ * Accumulated energy consumption of various consumers while on battery.
+ * If energy consumer data is unavailable this will be null.
+ */
+ @GuardedBy("this")
+ MeasuredEnergyStats mBatteryMeasuredEnergyStats;
+
+ /**
* These provide time bases that discount the time the device is plugged
* in to power.
*/
@@ -1123,7 +1145,7 @@ public class BatteryStatsImpl extends BatteryStats {
mBatteryStatsHistory = null;
mHandler = null;
mPlatformIdleStateCallback = null;
- mRailEnergyDataCallback = null;
+ mMeasuredEnergyRetriever = null;
mUserInfoProvider = null;
mConstants = new Constants(mHandler);
clearHistoryLocked();
@@ -1424,7 +1446,8 @@ public class BatteryStatsImpl extends BatteryStats {
* @param in the parcel to read from
* @return the Counter or null.
*/
- public static @Nullable Counter readCounterFromParcel(TimeBase timeBase, Parcel in) {
+ @Nullable
+ public static Counter readCounterFromParcel(TimeBase timeBase, Parcel in) {
if (in.readInt() == 0) {
return null;
}
@@ -3949,7 +3972,7 @@ public class BatteryStatsImpl extends BatteryStats {
@GuardedBy("this")
public void updateTimeBasesLocked(boolean unplugged, int screenState, long uptimeUs,
long realtimeUs) {
- final boolean screenOff = !isScreenOn(screenState);
+ final boolean screenOff = !Display.isOnState(screenState);
final boolean updateOnBatteryTimeBase = unplugged != mOnBatteryTimeBase.isRunning();
final boolean updateOnBatteryScreenOffTimeBase =
(unplugged && screenOff) != mOnBatteryScreenOffTimeBase.isRunning();
@@ -5012,16 +5035,16 @@ public class BatteryStatsImpl extends BatteryStats {
}
boolean updateHistory = false;
- if (isScreenDoze(state) && !isScreenDoze(oldState)) {
+ if (Display.isDozeState(state) && !Display.isDozeState(oldState)) {
mHistoryCur.states |= HistoryItem.STATE_SCREEN_DOZE_FLAG;
mScreenDozeTimer.startRunningLocked(elapsedRealtimeMs);
updateHistory = true;
- } else if (isScreenDoze(oldState) && !isScreenDoze(state)) {
+ } else if (Display.isDozeState(oldState) && !Display.isDozeState(state)) {
mHistoryCur.states &= ~HistoryItem.STATE_SCREEN_DOZE_FLAG;
mScreenDozeTimer.stopRunningLocked(elapsedRealtimeMs);
updateHistory = true;
}
- if (isScreenOn(state)) {
+ if (Display.isOnState(state)) {
mHistoryCur.states |= HistoryItem.STATE_SCREEN_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Screen on to: "
+ Integer.toHexString(mHistoryCur.states));
@@ -5031,7 +5054,7 @@ public class BatteryStatsImpl extends BatteryStats {
.startRunningLocked(elapsedRealtimeMs);
}
updateHistory = true;
- } else if (isScreenOn(oldState)) {
+ } else if (Display.isOnState(oldState)) {
mHistoryCur.states &= ~HistoryItem.STATE_SCREEN_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Screen off to: "
+ Integer.toHexString(mHistoryCur.states));
@@ -5047,15 +5070,21 @@ public class BatteryStatsImpl extends BatteryStats {
+ Display.stateToString(state));
addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
}
- mExternalSync.scheduleCpuSyncDueToScreenStateChange(
- mOnBatteryTimeBase.isRunning(), mOnBatteryScreenOffTimeBase.isRunning());
- if (isScreenOn(state)) {
+ int updateFlag = ExternalStatsSync.UPDATE_CPU;
+ if (mBatteryMeasuredEnergyStats != null && mBatteryMeasuredEnergyStats.hasSubsystem(
+ MeasuredEnergyArray.SUBSYSTEM_DISPLAY)) {
+ updateFlag |= ExternalStatsSync.UPDATE_ENERGY;
+ }
+ mExternalSync.scheduleSyncDueToScreenStateChange(updateFlag,
+ mOnBatteryTimeBase.isRunning(), mOnBatteryScreenOffTimeBase.isRunning(),
+ mScreenState);
+ if (Display.isOnState(state)) {
updateTimeBasesLocked(mOnBatteryTimeBase.isRunning(), state,
uptimeMs * 1000, elapsedRealtimeMs * 1000);
// Fake a wake lock, so we consider the device waked as long as the screen is on.
noteStartWakeLocked(-1, -1, null, "screen", null, WAKE_TYPE_PARTIAL, false,
elapsedRealtimeMs, uptimeMs);
- } else if (isScreenOn(oldState)) {
+ } else if (Display.isOnState(oldState)) {
noteStopWakeLocked(-1, -1, null, "screen", "screen", WAKE_TYPE_PARTIAL,
elapsedRealtimeMs, uptimeMs);
updateTimeBasesLocked(mOnBatteryTimeBase.isRunning(), state,
@@ -7039,6 +7068,26 @@ public class BatteryStatsImpl extends BatteryStats {
}
}
+ @Override
+ public long getScreenOnEnergy() {
+ if (mBatteryMeasuredEnergyStats == null || !mBatteryMeasuredEnergyStats.hasSubsystem(
+ MeasuredEnergyArray.SUBSYSTEM_DISPLAY)) {
+ return ENERGY_DATA_UNAVAILABLE;
+ }
+ return mBatteryMeasuredEnergyStats.getAccumulatedBucketEnergy(
+ MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_ON);
+ }
+
+ @Override
+ public long getScreenDozeEnergy() {
+ if (mBatteryMeasuredEnergyStats == null || !mBatteryMeasuredEnergyStats.hasSubsystem(
+ MeasuredEnergyArray.SUBSYSTEM_DISPLAY)) {
+ return ENERGY_DATA_UNAVAILABLE;
+ }
+ return mBatteryMeasuredEnergyStats.getAccumulatedBucketEnergy(
+ MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_DOZE);
+ }
+
@Override public long getStartClockTime() {
final long currentTimeMs = System.currentTimeMillis();
if ((currentTimeMs > MILLISECONDS_IN_YEAR
@@ -10457,12 +10506,12 @@ public class BatteryStatsImpl extends BatteryStats {
}
public BatteryStatsImpl(File systemDir, Handler handler, PlatformIdleStateCallback cb,
- RailEnergyDataCallback railStatsCb, UserInfoProvider userInfoProvider) {
- this(new SystemClocks(), systemDir, handler, cb, railStatsCb, userInfoProvider);
+ MeasuredEnergyRetriever energyStatsCb, UserInfoProvider userInfoProvider) {
+ this(new SystemClocks(), systemDir, handler, cb, energyStatsCb, userInfoProvider);
}
private BatteryStatsImpl(Clocks clocks, File systemDir, Handler handler,
- PlatformIdleStateCallback cb, RailEnergyDataCallback railStatsCb,
+ PlatformIdleStateCallback cb, MeasuredEnergyRetriever energyStatsCb,
UserInfoProvider userInfoProvider) {
init(clocks);
@@ -10563,12 +10612,19 @@ public class BatteryStatsImpl extends BatteryStats {
clearHistoryLocked();
updateDailyDeadlineLocked();
mPlatformIdleStateCallback = cb;
- mRailEnergyDataCallback = railStatsCb;
+ mMeasuredEnergyRetriever = energyStatsCb;
mUserInfoProvider = userInfoProvider;
// Notify statsd that the system is initially not in doze.
mDeviceIdleMode = DEVICE_IDLE_MODE_OFF;
FrameworkStatsLog.write(FrameworkStatsLog.DEVICE_IDLE_MODE_STATE_CHANGED, mDeviceIdleMode);
+
+ final MeasuredEnergyArray energyStats = mMeasuredEnergyRetriever.getEnergyConsumptionData();
+ // If measured energy is not available, it is not supported and
+ // mBatteryMeasuredEnergyStats should be left null.
+ if (energyStats != null) {
+ mBatteryMeasuredEnergyStats = new MeasuredEnergyStats(energyStats, mScreenState);
+ }
}
@UnsupportedAppUsage
@@ -10588,7 +10644,7 @@ public class BatteryStatsImpl extends BatteryStats {
mBatteryStatsHistory = new BatteryStatsHistory(this, mHistoryBuffer);
readFromParcel(p);
mPlatformIdleStateCallback = null;
- mRailEnergyDataCallback = null;
+ mMeasuredEnergyRetriever = null;
}
public void setPowerProfileLocked(PowerProfile profile) {
@@ -11097,19 +11153,6 @@ public class BatteryStatsImpl extends BatteryStats {
return mCharging;
}
- public boolean isScreenOn(int state) {
- return state == Display.STATE_ON || state == Display.STATE_VR
- || state == Display.STATE_ON_SUSPEND;
- }
-
- public boolean isScreenOff(int state) {
- return state == Display.STATE_OFF;
- }
-
- public boolean isScreenDoze(int state) {
- return state == Display.STATE_DOZE || state == Display.STATE_DOZE_SUSPEND;
- }
-
void initTimes(long uptimeUs, long realtimeUs) {
mStartClockTimeMs = System.currentTimeMillis();
mOnBatteryTimeBase.init(uptimeUs, realtimeUs);
@@ -11152,11 +11195,11 @@ public class BatteryStatsImpl extends BatteryStats {
mOnBatteryTimeBase.reset(uptimeUs, realtimeUs);
mOnBatteryScreenOffTimeBase.reset(uptimeUs, realtimeUs);
if ((mHistoryCur.states&HistoryItem.STATE_BATTERY_PLUGGED_FLAG) == 0) {
- if (isScreenOn(mScreenState)) {
+ if (Display.isOnState(mScreenState)) {
mDischargeScreenOnUnplugLevel = mHistoryCur.batteryLevel;
mDischargeScreenDozeUnplugLevel = 0;
mDischargeScreenOffUnplugLevel = 0;
- } else if (isScreenDoze(mScreenState)) {
+ } else if (Display.isDozeState(mScreenState)) {
mDischargeScreenOnUnplugLevel = 0;
mDischargeScreenDozeUnplugLevel = mHistoryCur.batteryLevel;
mDischargeScreenOffUnplugLevel = 0;
@@ -11286,6 +11329,11 @@ public class BatteryStatsImpl extends BatteryStats {
mTmpRailStats.reset();
+ if (mBatteryMeasuredEnergyStats != null) {
+ mBatteryMeasuredEnergyStats.reset();
+ mExternalSync.scheduleSync("reset", ExternalStatsSync.UPDATE_ENERGY);
+ }
+
resetIfNotNull(mSystemServerCpuTimesUs, false, elapsedRealtimeUs);
resetIfNotNull(mSystemServerThreadCpuTimesUs, false, elapsedRealtimeUs);
resetIfNotNull(mBinderThreadCpuTimesUs, false, elapsedRealtimeUs);
@@ -11339,19 +11387,19 @@ public class BatteryStatsImpl extends BatteryStats {
}
private void updateOldDischargeScreenLevelLocked(int state) {
- if (isScreenOn(state)) {
+ if (Display.isOnState(state)) {
int diff = mDischargeScreenOnUnplugLevel - mDischargeCurrentLevel;
if (diff > 0) {
mDischargeAmountScreenOn += diff;
mDischargeAmountScreenOnSinceCharge += diff;
}
- } else if (isScreenDoze(state)) {
+ } else if (Display.isDozeState(state)) {
int diff = mDischargeScreenDozeUnplugLevel - mDischargeCurrentLevel;
if (diff > 0) {
mDischargeAmountScreenDoze += diff;
mDischargeAmountScreenDozeSinceCharge += diff;
}
- } else if (isScreenOff(state)){
+ } else if (Display.isOffState(state)) {
int diff = mDischargeScreenOffUnplugLevel - mDischargeCurrentLevel;
if (diff > 0) {
mDischargeAmountScreenOff += diff;
@@ -11361,15 +11409,15 @@ public class BatteryStatsImpl extends BatteryStats {
}
private void updateNewDischargeScreenLevelLocked(int state) {
- if (isScreenOn(state)) {
+ if (Display.isOnState(state)) {
mDischargeScreenOnUnplugLevel = mDischargeCurrentLevel;
mDischargeScreenOffUnplugLevel = 0;
mDischargeScreenDozeUnplugLevel = 0;
- } else if (isScreenDoze(state)){
+ } else if (Display.isDozeState(state)) {
mDischargeScreenOnUnplugLevel = 0;
mDischargeScreenDozeUnplugLevel = mDischargeCurrentLevel;
mDischargeScreenOffUnplugLevel = 0;
- } else if (isScreenOff(state)) {
+ } else if (Display.isOffState(state)) {
mDischargeScreenOnUnplugLevel = 0;
mDischargeScreenDozeUnplugLevel = 0;
mDischargeScreenOffUnplugLevel = mDischargeCurrentLevel;
@@ -12163,10 +12211,25 @@ public class BatteryStatsImpl extends BatteryStats {
* Read and record Rail Energy data.
*/
public void updateRailStatsLocked() {
- if (mRailEnergyDataCallback == null || !mTmpRailStats.isRailStatsAvailable()) {
+ if (mMeasuredEnergyRetriever == null || !mTmpRailStats.isRailStatsAvailable()) {
return;
}
- mRailEnergyDataCallback.fillRailDataStats(mTmpRailStats);
+ mMeasuredEnergyRetriever.fillRailDataStats(mTmpRailStats);
+ }
+
+ /**
+ * Get energy consumed (in microjoules) by a set of subsystems from the {@link
+ * MeasuredEnergyRetriever}, if available.
+ *
+ * @return a SparseLongArray that maps consumer id to energy consumed. Returns null if data is
+ * unavailable.
+ */
+ @Nullable
+ public MeasuredEnergyArray getEnergyConsumptionDataLocked() {
+ if (mMeasuredEnergyRetriever == null) {
+ return null;
+ }
+ return mMeasuredEnergyRetriever.getEnergyConsumptionData();
}
/**
@@ -12428,6 +12491,21 @@ public class BatteryStatsImpl extends BatteryStats {
}
/**
+ * Update energy consumption data with a new snapshot of energy data.
+ * Generally this should only be called from BatteryExternalStatsWorker.
+ *
+ * @param energyStats latest energy data to update with.
+ */
+ @GuardedBy("this")
+ public void updateMeasuredEnergyStatsLocked(@NonNull MeasuredEnergyArray energyStats,
+ int screenState) {
+ if (mBatteryMeasuredEnergyStats != null) {
+ mBatteryMeasuredEnergyStats.update(energyStats, screenState,
+ mOnBatteryTimeBase.isRunning());
+ }
+ }
+
+ /**
* Mark the current partial timers as gone through a collection so that they will be
* considered in the next cpu times distribution to wakelock holders.
*/
@@ -12919,11 +12997,11 @@ public class BatteryStatsImpl extends BatteryStats {
}
addHistoryRecordLocked(mSecRealtime, mSecUptime);
mDischargeCurrentLevel = mDischargeUnplugLevel = level;
- if (isScreenOn(screenState)) {
+ if (Display.isOnState(screenState)) {
mDischargeScreenOnUnplugLevel = level;
mDischargeScreenDozeUnplugLevel = 0;
mDischargeScreenOffUnplugLevel = 0;
- } else if (isScreenDoze(screenState)) {
+ } else if (Display.isDozeState(screenState)) {
mDischargeScreenOnUnplugLevel = 0;
mDischargeScreenDozeUnplugLevel = level;
mDischargeScreenOffUnplugLevel = 0;
@@ -13079,7 +13157,7 @@ public class BatteryStatsImpl extends BatteryStats {
final long chargeDiff = mHistoryCur.batteryChargeUAh - chargeUAh;
mDischargeCounter.addCountLocked(chargeDiff);
mDischargeScreenOffCounter.addCountLocked(chargeDiff);
- if (isScreenDoze(mScreenState)) {
+ if (Display.isDozeState(mScreenState)) {
mDischargeScreenDozeCounter.addCountLocked(chargeDiff);
}
if (mDeviceIdleMode == DEVICE_IDLE_MODE_LIGHT) {
@@ -13130,7 +13208,7 @@ public class BatteryStatsImpl extends BatteryStats {
final long chargeDiff = mHistoryCur.batteryChargeUAh - chargeUAh;
mDischargeCounter.addCountLocked(chargeDiff);
mDischargeScreenOffCounter.addCountLocked(chargeDiff);
- if (isScreenDoze(mScreenState)) {
+ if (Display.isDozeState(mScreenState)) {
mDischargeScreenDozeCounter.addCountLocked(chargeDiff);
}
if (mDeviceIdleMode == DEVICE_IDLE_MODE_LIGHT) {
@@ -13584,7 +13662,7 @@ public class BatteryStatsImpl extends BatteryStats {
public int getDischargeAmountScreenOn() {
synchronized(this) {
int val = mDischargeAmountScreenOn;
- if (mOnBattery && isScreenOn(mScreenState)
+ if (mOnBattery && Display.isOnState(mScreenState)
&& mDischargeCurrentLevel < mDischargeScreenOnUnplugLevel) {
val += mDischargeScreenOnUnplugLevel-mDischargeCurrentLevel;
}
@@ -13596,7 +13674,7 @@ public class BatteryStatsImpl extends BatteryStats {
public int getDischargeAmountScreenOnSinceCharge() {
synchronized(this) {
int val = mDischargeAmountScreenOnSinceCharge;
- if (mOnBattery && isScreenOn(mScreenState)
+ if (mOnBattery && Display.isOnState(mScreenState)
&& mDischargeCurrentLevel < mDischargeScreenOnUnplugLevel) {
val += mDischargeScreenOnUnplugLevel-mDischargeCurrentLevel;
}
@@ -13609,7 +13687,7 @@ public class BatteryStatsImpl extends BatteryStats {
public int getDischargeAmountScreenOff() {
synchronized(this) {
int val = mDischargeAmountScreenOff;
- if (mOnBattery && isScreenOff(mScreenState)
+ if (mOnBattery && Display.isOffState(mScreenState)
&& mDischargeCurrentLevel < mDischargeScreenOffUnplugLevel) {
val += mDischargeScreenOffUnplugLevel-mDischargeCurrentLevel;
}
@@ -13622,7 +13700,7 @@ public class BatteryStatsImpl extends BatteryStats {
public int getDischargeAmountScreenOffSinceCharge() {
synchronized(this) {
int val = mDischargeAmountScreenOffSinceCharge;
- if (mOnBattery && isScreenOff(mScreenState)
+ if (mOnBattery && Display.isOffState(mScreenState)
&& mDischargeCurrentLevel < mDischargeScreenOffUnplugLevel) {
val += mDischargeScreenOffUnplugLevel-mDischargeCurrentLevel;
}
@@ -13635,7 +13713,7 @@ public class BatteryStatsImpl extends BatteryStats {
public int getDischargeAmountScreenDoze() {
synchronized(this) {
int val = mDischargeAmountScreenDoze;
- if (mOnBattery && isScreenDoze(mScreenState)
+ if (mOnBattery && Display.isDozeState(mScreenState)
&& mDischargeCurrentLevel < mDischargeScreenDozeUnplugLevel) {
val += mDischargeScreenDozeUnplugLevel-mDischargeCurrentLevel;
}
@@ -13647,7 +13725,7 @@ public class BatteryStatsImpl extends BatteryStats {
public int getDischargeAmountScreenDozeSinceCharge() {
synchronized(this) {
int val = mDischargeAmountScreenDozeSinceCharge;
- if (mOnBattery && isScreenDoze(mScreenState)
+ if (mOnBattery && Display.isDozeState(mScreenState)
&& mDischargeCurrentLevel < mDischargeScreenDozeUnplugLevel) {
val += mDischargeScreenDozeUnplugLevel-mDischargeCurrentLevel;
}
@@ -14129,6 +14207,19 @@ public class BatteryStatsImpl extends BatteryStats {
}
}
+ /**
+ * Dump measured energy stats
+ */
+ @GuardedBy("this")
+ public void dumpMeasuredEnergyStatsLocked(PrintWriter pw) {
+ if (mBatteryMeasuredEnergyStats == null) return;
+ final IndentingPrintWriter iPw = new IndentingPrintWriter(pw, " ");
+ iPw.println("On battery measured energy stats:");
+ iPw.increaseIndent();
+ mBatteryMeasuredEnergyStats.dump(iPw);
+ iPw.decreaseIndent();
+ }
+
final ReentrantLock mWriteLock = new ReentrantLock();
public void writeAsyncLocked() {
@@ -14504,6 +14595,8 @@ public class BatteryStatsImpl extends BatteryStats {
mNextMaxDailyDeadlineMs = in.readLong();
mBatteryTimeToFullSeconds = in.readLong();
+ MeasuredEnergyStats.readSummaryFromParcel(mBatteryMeasuredEnergyStats, in);
+
mStartCount++;
mScreenState = Display.STATE_UNKNOWN;
@@ -14997,6 +15090,8 @@ public class BatteryStatsImpl extends BatteryStats {
out.writeLong(mNextMaxDailyDeadlineMs);
out.writeLong(mBatteryTimeToFullSeconds);
+ MeasuredEnergyStats.writeSummaryToParcel(mBatteryMeasuredEnergyStats, out);
+
mScreenOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
mScreenDozeTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
@@ -15581,6 +15676,10 @@ public class BatteryStatsImpl extends BatteryStats {
mLastWriteTimeMs = in.readLong();
mBatteryTimeToFullSeconds = in.readLong();
+ if (in.readInt() != 0) {
+ mBatteryMeasuredEnergyStats = new MeasuredEnergyStats(in);
+ }
+
mRpmStats.clear();
int NRPMS = in.readInt();
for (int irpm = 0; irpm < NRPMS; irpm++) {
@@ -15783,6 +15882,13 @@ public class BatteryStatsImpl extends BatteryStats {
out.writeLong(mLastWriteTimeMs);
out.writeLong(mBatteryTimeToFullSeconds);
+ if (mBatteryMeasuredEnergyStats != null) {
+ out.writeInt(1);
+ mBatteryMeasuredEnergyStats.writeToParcel(out);
+ } else {
+ out.writeInt(0);
+ }
+
out.writeInt(mRpmStats.size());
for (Map.Entry<String, SamplingTimer> ent : mRpmStats.entrySet()) {
SamplingTimer rpmt = ent.getValue();
@@ -16036,5 +16142,8 @@ public class BatteryStatsImpl extends BatteryStats {
pw.println();
dumpConstantsLocked(pw);
+
+ pw.println();
+ dumpMeasuredEnergyStatsLocked(pw);
}
}
diff --git a/core/java/com/android/internal/power/MeasuredEnergyArray.java b/core/java/com/android/internal/power/MeasuredEnergyArray.java
new file mode 100644
index 000000000000..1f6dc260a197
--- /dev/null
+++ b/core/java/com/android/internal/power/MeasuredEnergyArray.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.power;
+
+
+import android.annotation.IntDef;
+
+import com.android.internal.os.RailStats;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Interface to provide subsystem energy data.
+ * TODO: replace this and {@link RailStats} once b/173077356 is done
+ */
+public interface MeasuredEnergyArray {
+ int SUBSYSTEM_UNKNOWN = -1;
+ int SUBSYSTEM_DISPLAY = 0;
+ int NUMBER_SUBSYSTEMS = 1;
+ String[] SUBSYSTEM_NAMES = {"display"};
+
+
+ @IntDef(prefix = { "SUBSYSTEM_" }, value = {
+ SUBSYSTEM_UNKNOWN,
+ SUBSYSTEM_DISPLAY,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface MeasuredEnergySubsystem {}
+
+ /**
+ * Get the subsystem at an index in array.
+ *
+ * @param index into the array.
+ * @return subsystem.
+ */
+ @MeasuredEnergySubsystem
+ int getSubsystem(int index);
+
+ /**
+ * Get the energy (in microjoules) consumed since boot of the subsystem at an index.
+ *
+ * @param index into the array.
+ * @return energy (in microjoules) consumed since boot.
+ */
+ long getEnergy(int index);
+
+ /**
+ * Return number of subsystems in the array.
+ */
+ int size();
+}
diff --git a/core/java/com/android/internal/power/MeasuredEnergyStats.java b/core/java/com/android/internal/power/MeasuredEnergyStats.java
new file mode 100644
index 000000000000..7b6e0790e14f
--- /dev/null
+++ b/core/java/com/android/internal/power/MeasuredEnergyStats.java
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.power;
+
+
+import android.annotation.IntDef;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.view.Display;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.power.MeasuredEnergyArray.MeasuredEnergySubsystem;
+
+import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
+
+/**
+ * MeasuredEnergyStats adds up the measured energy usage of various subsystems
+ */
+@VisibleForTesting
+public class MeasuredEnergyStats {
+ private static final long UNAVAILABLE = -1;
+ private static final long RESET = -2;
+
+ public static final int ENERGY_BUCKET_UNKNOWN = -1;
+ public static final int ENERGY_BUCKET_SCREEN_ON = 0;
+ public static final int ENERGY_BUCKET_SCREEN_DOZE = 1;
+ public static final int ENERGY_BUCKET_SCREEN_OTHER = 2;
+ public static final int NUMBER_ENERGY_BUCKETS = 3;
+ private static final String[] ENERGY_BUCKET_NAMES =
+ {"screen-on", "screen-doze", "screen-other"};
+
+ @IntDef(prefix = {"ENERGY_BUCKET_"}, value = {
+ ENERGY_BUCKET_UNKNOWN,
+ ENERGY_BUCKET_SCREEN_ON,
+ ENERGY_BUCKET_SCREEN_DOZE,
+ ENERGY_BUCKET_SCREEN_OTHER,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface EnergyBucket {
+ }
+
+ /**
+ * Energy snapshots from the last time each {@link MeasuredEnergySubsystem} was updated.
+ * An energy snapshot will be set to {@link #UNAVAILABLE} if the subsystem has never been
+ * updated.
+ * An energy snapshot will be set to {@link #RESET} on a reset. A subsystems energy will
+ * need to be updated at least twice to start accumulating energy again.
+ */
+ private final long[] mMeasuredEnergySnapshots =
+ new long[MeasuredEnergyArray.NUMBER_SUBSYSTEMS];
+
+ /**
+ * Total energy in microjoules since the last reset that an {@link EnergyBucket} has
+ * accumulated.
+ *
+ * Warning: Long array is used for access speed. If the number of supported subsystems
+ * becomes too large, consider using an alternate data structure.
+ */
+ private final long[] mAccumulatedEnergiesMicroJoules = new long[NUMBER_ENERGY_BUCKETS];
+
+ /**
+ * Last known screen state.
+ */
+ private int mLastScreenState;
+
+ public MeasuredEnergyStats(MeasuredEnergyArray energyArray, int screenState) {
+ Arrays.fill(mMeasuredEnergySnapshots, UNAVAILABLE);
+
+ update(energyArray, screenState, false);
+ }
+
+ public MeasuredEnergyStats(Parcel in) {
+ in.readLongArray(mAccumulatedEnergiesMicroJoules);
+ }
+
+ /**
+ * Constructor for creating a temp MeasuredEnergyStats
+ * See {@link #readSummaryFromParcel(MeasuredEnergyStats, Parcel)}
+ */
+ private MeasuredEnergyStats() {
+ Arrays.fill(mMeasuredEnergySnapshots, UNAVAILABLE);
+ }
+
+ /** Write to parcel */
+ public void writeToParcel(Parcel out) {
+ out.writeLongArray(mAccumulatedEnergiesMicroJoules);
+ }
+
+ /**
+ * Read from summary parcel.
+ * Note: Measured subsystem availability may be different from when the summary parcel was
+ * written.
+ */
+ private void readSummaryFromParcel(Parcel in) {
+ final int size = in.readInt();
+ for (int i = 0; i < size; i++) {
+ final int bucket = in.readInt();
+ final long energyUJ = in.readLong();
+
+ final int subsystem = getSubsystem(bucket);
+ // Only accept the summary energy if subsystem is currently available
+ if (subsystem != MeasuredEnergyArray.SUBSYSTEM_UNKNOWN
+ && mMeasuredEnergySnapshots[subsystem] != UNAVAILABLE) {
+ mAccumulatedEnergiesMicroJoules[bucket] = energyUJ;
+ }
+ }
+ }
+
+ /**
+ * Write to summary parcel.
+ * Note: Measured subsystem availability may be different when the summary parcel is read.
+ * Note: {@link com.android.internal.os.BatteryStatsImpl#VERSION} must be updated if summary
+ * parceling changes.
+ */
+ private void writeSummaryToParcel(Parcel out) {
+ final int sizePos = out.dataPosition();
+ out.writeInt(0);
+ int size = 0;
+ // Write only the buckets with reported energy
+ for (int i = 0; i < NUMBER_ENERGY_BUCKETS; i++) {
+ final int subsystem = getSubsystem(i);
+ if (mMeasuredEnergySnapshots[subsystem] == UNAVAILABLE) continue;
+
+ out.writeInt(i);
+ out.writeLong(mAccumulatedEnergiesMicroJoules[i]);
+ size++;
+ }
+ final int currPos = out.dataPosition();
+ out.setDataPosition(sizePos);
+ out.writeInt(size);
+ out.setDataPosition(currPos);
+ }
+
+ /**
+ * Update with the latest measured energies and device state.
+ *
+ * @param energyArray measured energy array for some subsystems.
+ * @param screenState screen state to attribute disaply energy to after this update.
+ * @param accumulate whether or not to accumulate the latest energy
+ */
+ public void update(MeasuredEnergyArray energyArray, int screenState, boolean accumulate) {
+ final int size = energyArray.size();
+ if (!accumulate) {
+ for (int i = 0; i < size; i++) {
+ final int subsystem = energyArray.getSubsystem(i);
+ mMeasuredEnergySnapshots[subsystem] = energyArray.getEnergy(i);
+ }
+ } else {
+ for (int i = 0; i < size; i++) {
+ final int subsystem = energyArray.getSubsystem(i);
+ final long newEnergyUJ = energyArray.getEnergy(i);
+ final long oldEnergyUJ = mMeasuredEnergySnapshots[subsystem];
+ mMeasuredEnergySnapshots[subsystem] = newEnergyUJ;
+
+ // This is the first valid energy, skip accumulating the delta
+ if (oldEnergyUJ < 0) continue;
+ final long deltaUJ = newEnergyUJ - oldEnergyUJ;
+
+ final int bucket = getEnergyBucket(subsystem, mLastScreenState);
+ mAccumulatedEnergiesMicroJoules[bucket] += deltaUJ;
+ }
+ }
+ mLastScreenState = screenState;
+ }
+
+ /**
+ * Map {@link MeasuredEnergySubsystem} and device state to an {@link EnergyBucket}.
+ * Keep in sync with {@link #getSubsystem}
+ */
+ @EnergyBucket
+ private int getEnergyBucket(@MeasuredEnergySubsystem int subsystem, int screenState) {
+ switch (subsystem) {
+ case MeasuredEnergyArray.SUBSYSTEM_DISPLAY:
+ if (Display.isOnState(screenState)) {
+ return ENERGY_BUCKET_SCREEN_ON;
+ } else if (Display.isDozeState(screenState)) {
+ return ENERGY_BUCKET_SCREEN_DOZE;
+ } else {
+ return ENERGY_BUCKET_SCREEN_OTHER;
+ }
+ default:
+ return ENERGY_BUCKET_UNKNOWN;
+ }
+ }
+
+ /**
+ * Map {@link EnergyBucket} to a {@link MeasuredEnergySubsystem}.
+ * Keep in sync with {@link #getEnergyBucket}
+ */
+ @MeasuredEnergySubsystem
+ private int getSubsystem(@EnergyBucket int bucket) {
+ switch (bucket) {
+ case ENERGY_BUCKET_SCREEN_ON: //fallthrough
+ case ENERGY_BUCKET_SCREEN_DOZE: //fallthrough
+ case ENERGY_BUCKET_SCREEN_OTHER:
+ return MeasuredEnergyArray.SUBSYSTEM_DISPLAY;
+ default:
+ return MeasuredEnergyArray.SUBSYSTEM_UNKNOWN;
+ }
+ }
+
+ /**
+ * Check if a subsystem's measured energy is available.
+ * @param subsystem which subsystem.
+ * @return true if subsystem is avaiable.
+ */
+ public boolean hasSubsystem(@MeasuredEnergySubsystem int subsystem) {
+ return mMeasuredEnergySnapshots[subsystem] != UNAVAILABLE;
+ }
+
+ /**
+ * Return accumulated energy (in microjoules) since last reset.
+ */
+ public long getAccumulatedBucketEnergy(@EnergyBucket int bucket) {
+ return mAccumulatedEnergiesMicroJoules[bucket];
+ }
+
+ /**
+ * Populate a MeasuredEnergyStats from a parcel. If the stats is null, consume and
+ * ignore the parcelled data.
+ */
+ public static void readSummaryFromParcel(@Nullable MeasuredEnergyStats stats, Parcel in) {
+ // Check if any MeasuredEnergyStats exists on the parcel
+ if (in.readInt() == 0) return;
+
+ // If stats is null, create a placeholder MeasuredEnergyStats to consume the parcel data
+ final MeasuredEnergyStats mes = stats != null ? stats : new MeasuredEnergyStats();
+ mes.readSummaryFromParcel(in);
+ }
+
+ /**
+ * Write a MeasuredEnergyStats to a parcel. If the stats is null, just write a 0.
+ */
+ public static void writeSummaryToParcel(@Nullable MeasuredEnergyStats stats,
+ Parcel dest) {
+ if (stats == null) {
+ dest.writeInt(0);
+ return;
+ }
+ dest.writeInt(1);
+ stats.writeSummaryToParcel(dest);
+ }
+
+ /**
+ * Reset accumulated energy.
+ */
+ public void reset() {
+ for (int i = 0; i < MeasuredEnergyArray.NUMBER_SUBSYSTEMS; i++) {
+ // Leave subsystems marked as unavailable alone.
+ if (mMeasuredEnergySnapshots[i] == UNAVAILABLE) continue;
+ mMeasuredEnergySnapshots[i] = RESET;
+ }
+ Arrays.fill(mAccumulatedEnergiesMicroJoules, 0);
+ }
+
+ /**
+ * Dump debug data.
+ */
+ public void dump(PrintWriter pw) {
+ pw.println("Measured energy snapshot (microjoules):");
+ pw.print(" ");
+ for (int i = 0; i < MeasuredEnergyArray.NUMBER_SUBSYSTEMS; i++) {
+ final long energyUJ = mMeasuredEnergySnapshots[i];
+ if (energyUJ == UNAVAILABLE) continue;
+ pw.print(MeasuredEnergyArray.SUBSYSTEM_NAMES[i]);
+ pw.print(" : ");
+ if (energyUJ == RESET) {
+ pw.print("reset");
+ } else {
+ pw.print(energyUJ);
+ }
+ if (i != MeasuredEnergyArray.NUMBER_SUBSYSTEMS - 1) {
+ pw.print(", ");
+ }
+ }
+ pw.println();
+
+ pw.println("Accumulated energy since last reset (microjoules):");
+ pw.print(" ");
+ for (int i = 0; i < NUMBER_ENERGY_BUCKETS; i++) {
+ pw.print(ENERGY_BUCKET_NAMES[i]);
+ pw.print(" : ");
+ pw.print(mAccumulatedEnergiesMicroJoules[i]);
+ if (i != NUMBER_ENERGY_BUCKETS - 1) {
+ pw.print(", ");
+ }
+ }
+ pw.println();
+ }
+}
diff --git a/core/java/com/android/internal/util/function/pooled/OWNERS b/core/java/com/android/internal/util/function/pooled/OWNERS
new file mode 100644
index 000000000000..da723b3b67da
--- /dev/null
+++ b/core/java/com/android/internal/util/function/pooled/OWNERS
@@ -0,0 +1 @@
+eugenesusla@google.com \ No newline at end of file
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index e7e9c31ef90e..6337680147a5 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -41,14 +41,21 @@ static struct {
jmethodID dispatchVsync;
jmethodID dispatchHotplug;
jmethodID dispatchConfigChanged;
+ jmethodID dispatchFrameRateOverrides;
+
+ struct {
+ jclass clazz;
+ jmethodID init;
+ } frameRateOverrideClassInfo;
+
} gDisplayEventReceiverClassInfo;
class NativeDisplayEventReceiver : public DisplayEventDispatcher {
public:
- NativeDisplayEventReceiver(JNIEnv* env,
- jobject receiverWeak, const sp<MessageQueue>& messageQueue, jint vsyncSource,
- jint configChanged);
+ NativeDisplayEventReceiver(JNIEnv* env, jobject receiverWeak,
+ const sp<MessageQueue>& messageQueue, jint vsyncSource,
+ jint eventRegistration);
void dispose();
@@ -64,16 +71,17 @@ private:
void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override;
void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId,
int32_t configId, nsecs_t vsyncPeriod) override;
+ void dispatchFrameRateOverrides(nsecs_t timestamp, PhysicalDisplayId displayId,
+ std::vector<FrameRateOverride> overrides) override;
void dispatchNullEvent(nsecs_t timestamp, PhysicalDisplayId displayId) override {}
};
-
-NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env,
- jobject receiverWeak, const sp<MessageQueue>& messageQueue, jint vsyncSource,
- jint configChanged) :
- DisplayEventDispatcher(messageQueue->getLooper(),
- static_cast<ISurfaceComposer::VsyncSource>(vsyncSource),
- static_cast<ISurfaceComposer::ConfigChanged>(configChanged)),
+NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env, jobject receiverWeak,
+ const sp<MessageQueue>& messageQueue,
+ jint vsyncSource, jint eventRegistration)
+ : DisplayEventDispatcher(messageQueue->getLooper(),
+ static_cast<ISurfaceComposer::VsyncSource>(vsyncSource),
+ static_cast<ISurfaceComposer::EventRegistration>(eventRegistration)),
mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)),
mMessageQueue(messageQueue) {
ALOGV("receiver %p ~ Initializing display event receiver.", this);
@@ -137,16 +145,48 @@ void NativeDisplayEventReceiver::dispatchConfigChanged(
mMessageQueue->raiseAndClearException(env, "dispatchConfigChanged");
}
-static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
- jobject messageQueueObj, jint vsyncSource, jint configChanged) {
+void NativeDisplayEventReceiver::dispatchFrameRateOverrides(
+ nsecs_t timestamp, PhysicalDisplayId displayId, std::vector<FrameRateOverride> overrides) {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+
+ ScopedLocalRef<jobject> receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal));
+ if (receiverObj.get()) {
+ ALOGV("receiver %p ~ Invoking FrameRateOverride handler.", this);
+ const auto frameRateOverrideClass =
+ gDisplayEventReceiverClassInfo.frameRateOverrideClassInfo.clazz;
+ const auto frameRateOverrideInit =
+ gDisplayEventReceiverClassInfo.frameRateOverrideClassInfo.init;
+ auto frameRateOverrideInitObject =
+ env->NewObject(frameRateOverrideClass, frameRateOverrideInit, 0, 0);
+ auto frameRateOverrideArray = env->NewObjectArray(overrides.size(), frameRateOverrideClass,
+ frameRateOverrideInitObject);
+ for (size_t i = 0; i < overrides.size(); i++) {
+ auto FrameRateOverrideObject =
+ env->NewObject(frameRateOverrideClass, frameRateOverrideInit, overrides[i].uid,
+ overrides[i].frameRateHz);
+ env->SetObjectArrayElement(frameRateOverrideArray, i, FrameRateOverrideObject);
+ }
+
+ env->CallVoidMethod(receiverObj.get(),
+ gDisplayEventReceiverClassInfo.dispatchFrameRateOverrides, timestamp,
+ displayId.value, frameRateOverrideArray);
+ ALOGV("receiver %p ~ Returned from FrameRateOverride handler.", this);
+ }
+
+ mMessageQueue->raiseAndClearException(env, "dispatchConfigChanged");
+}
+
+static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak, jobject messageQueueObj,
+ jint vsyncSource, jint eventRegistration) {
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
if (messageQueue == NULL) {
jniThrowRuntimeException(env, "MessageQueue is not initialized.");
return 0;
}
- sp<NativeDisplayEventReceiver> receiver = new NativeDisplayEventReceiver(env,
- receiverWeak, messageQueue, vsyncSource, configChanged);
+ sp<NativeDisplayEventReceiver> receiver =
+ new NativeDisplayEventReceiver(env, receiverWeak, messageQueue, vsyncSource,
+ eventRegistration);
status_t status = receiver->initialize();
if (status) {
String8 message;
@@ -205,6 +245,18 @@ int register_android_view_DisplayEventReceiver(JNIEnv* env) {
gDisplayEventReceiverClassInfo.clazz, "dispatchHotplug", "(JJZ)V");
gDisplayEventReceiverClassInfo.dispatchConfigChanged = GetMethodIDOrDie(env,
gDisplayEventReceiverClassInfo.clazz, "dispatchConfigChanged", "(JJI)V");
+ gDisplayEventReceiverClassInfo.dispatchFrameRateOverrides =
+ GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz,
+ "dispatchFrameRateOverrides",
+ "(JJ[Landroid/view/DisplayEventReceiver$FrameRateOverride;)V");
+
+ jclass frameRateOverrideClazz =
+ FindClassOrDie(env, "android/view/DisplayEventReceiver$FrameRateOverride");
+ gDisplayEventReceiverClassInfo.frameRateOverrideClassInfo.clazz =
+ MakeGlobalRefOrDie(env, frameRateOverrideClazz);
+ gDisplayEventReceiverClassInfo.frameRateOverrideClassInfo.init =
+ GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.frameRateOverrideClassInfo.clazz,
+ "<init>", "(IF)V");
return res;
}
diff --git a/core/proto/OWNERS b/core/proto/OWNERS
index 542d26fa233e..5eeeb048e6d6 100644
--- a/core/proto/OWNERS
+++ b/core/proto/OWNERS
@@ -25,3 +25,18 @@ hyunyoungs@google.com
# Graphics stats
jreck@google.com
+
+# Temporary Block to assist in migration
+# Bug: 143080132
+per-file *enums.proto = baligh@google.com, yro@google.com, jeffreyhuang@google.com
+per-file *media_output_enum.proto = baligh@google.com, yro@google.com, jeffreyhuang@google.com
+per-file *networkcapabilities.proto = baligh@google.com, yro@google.com, jeffreyhuang@google.com
+per-file *data_stall_event.proto = baligh@google.com, yro@google.com, jeffreyhuang@google.com
+per-file *procstats_enum.proto = baligh@google.com, yro@google.com, jeffreyhuang@google.com
+per-file *usb.proto = baligh@google.com, yro@google.com, jeffreyhuang@google.com
+per-file *network_stack.proto = baligh@google.com, yro@google.com, jeffreyhuang@google.com
+per-file *tethering.proto = baligh@google.com, yro@google.com, jeffreyhuang@google.com
+per-file *dns_resolver.proto = baligh@google.com, yro@google.com, jeffreyhuang@google.com
+per-file *device_policy.proto = baligh@google.com, yro@google.com, jeffreyhuang@google.com
+per-file *launcher.proto = baligh@google.com, yro@google.com, jeffreyhuang@google.com
+per-file *mediametrics.proto = baligh@google.com, yro@google.com, jeffreyhuang@google.com
diff --git a/core/proto/android/server/accessibility.proto b/core/proto/android/server/accessibility.proto
new file mode 100644
index 000000000000..7fe7f0d5f3cc
--- /dev/null
+++ b/core/proto/android/server/accessibility.proto
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+
+import "frameworks/base/core/proto/android/typedef.proto";
+
+package com.android.server.accessibility;
+
+option java_multiple_files = true;
+
+/* The proto format trace entry for accessibility service */
+message AccessibilityDumpProto {
+}
diff --git a/core/proto/android/server/accessibilitytrace.proto b/core/proto/android/server/accessibilitytrace.proto
new file mode 100644
index 000000000000..1fc4a01936b1
--- /dev/null
+++ b/core/proto/android/server/accessibilitytrace.proto
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+
+import "frameworks/base/core/proto/android/server/accessibility.proto";
+import "frameworks/base/core/proto/android/server/windowmanagerservice.proto";
+
+package com.android.server.accessibility;
+
+option java_multiple_files = true;
+
+/* represents a file full of accessibility trace entries.
+ Encoded, it should start with 0x9 0x41 0x31 0x31 0x59 0x54 0x52 0x41 0x43 (.A11YTRAC), such
+ that they can be easily identified. */
+message AccessibilityTraceFileProto {
+
+ /* constant; MAGIC_NUMBER = (long) MAGIC_NUMBER_H << 32 | MagicNumber.MAGIC_NUMBER_L
+ (this is needed because enums have to be 32 bits and there's no nice way to put 64bit
+ constants into .proto files. */
+ enum MagicNumber {
+ INVALID = 0;
+ MAGIC_NUMBER_L = 0x59313141; /* A11Y (little-endian ASCII) */
+ MAGIC_NUMBER_H = 0x43415254; /* TRAC (little-endian ASCII) */
+ }
+
+ optional fixed64 magic_number = 1; /* Must be the first field, set to value in MagicNumber */
+ repeated AccessibilityTraceProto entry = 2;
+}
+
+/* one accessibility trace entry. */
+message AccessibilityTraceProto {
+ /* required: elapsed realtime in nanos since boot of when this entry was logged */
+ optional fixed64 elapsed_realtime_nanos = 1;
+ optional string calendar_time = 2;
+
+ optional string process_name = 3;
+ optional string thread_id_name = 4;
+
+ /* where the trace originated */
+ optional string where = 5;
+
+ optional string calling_pkg = 6;
+ optional string calling_params = 7;
+ optional string calling_stacks = 8;
+
+ optional AccessibilityDumpProto accessibility_service = 9;
+ optional com.android.server.wm.WindowManagerServiceDumpProto window_manager_service = 10;
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index ea667277efee..c9e8f719ebc5 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2557,6 +2557,10 @@
<permission android:name="android.permission.START_ACTIVITIES_FROM_BACKGROUND"
android:protectionLevel="signature|privileged|vendorPrivileged|oem|verifier" />
+ <!-- @SystemApi @hide Allows an application to start foreground services from background -->
+ <permission android:name="android.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND"
+ android:protectionLevel="signature|privileged|vendorPrivileged|oem|verifier" />
+
<!-- @SystemApi Must be required by activities that handle the intent action
{@link Intent#ACTION_SEND_SHOW_SUSPENDED_APP_DETAILS}. This is for use by apps that
hold {@link Manifest.permission#SUSPEND_APPS} to interact with the system.
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index c32e8dc94486..85b19e7de04b 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -303,6 +303,9 @@
<!-- Additional flag from base permission type: this permission will be granted to the
retail demo app, as defined by the OEM. -->
<flag name="retailDemo" value="0x1000000" />
+ <!-- Additional flag from base permission type: this permission will be granted to the
+ recents app. -->
+ <flag name="recents" value="0x2000000" />
</attr>
<!-- Flags indicating more context for a permission group. -->
diff --git a/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java b/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java
index c66bac6cc335..82d066f6ab16 100644
--- a/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java
+++ b/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java
@@ -23,7 +23,6 @@ import static org.junit.Assert.assertTrue;
import android.content.Context;
import android.content.res.AssetManager;
-import android.graphics.fonts.Font;
import android.graphics.fonts.FontCustomizationParser;
import android.graphics.fonts.FontFamily;
import android.graphics.fonts.SystemFonts;
@@ -49,7 +48,6 @@ import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
-import java.util.ArrayList;
import java.util.Locale;
@SmallTest
@@ -133,14 +131,14 @@ public class TypefaceSystemFallbackTest {
private static void buildSystemFallback(String xml,
FontCustomizationParser.Result oemCustomization, ArrayMap<String, Typeface> fontMap,
ArrayMap<String, FontFamily[]> fallbackMap) {
- final ArrayList<Font> availableFonts = new ArrayList<>();
try (FileOutputStream fos = new FileOutputStream(TEST_FONTS_XML)) {
fos.write(xml.getBytes(Charset.forName("UTF-8")));
} catch (IOException e) {
throw new RuntimeException(e);
}
+
final FontConfig.Alias[] aliases = SystemFonts.buildSystemFallback(TEST_FONTS_XML,
- TEST_FONT_DIR, oemCustomization, fallbackMap, availableFonts);
+ TEST_FONT_DIR, oemCustomization, fallbackMap);
Typeface.initSystemDefaultTypefaces(fontMap, fallbackMap, aliases);
}
@@ -156,12 +154,11 @@ public class TypefaceSystemFallbackTest {
public void testBuildSystemFallback() {
final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
- final ArrayList<Font> availableFonts = new ArrayList<>();
final FontCustomizationParser.Result oemCustomization =
new FontCustomizationParser.Result();
final FontConfig.Alias[] aliases = SystemFonts.buildSystemFallback(SYSTEM_FONTS_XML,
- SYSTEM_FONT_DIR, oemCustomization, fallbackMap, availableFonts);
+ SYSTEM_FONT_DIR, oemCustomization, fallbackMap);
assertNotNull(aliases);
assertFalse(fallbackMap.isEmpty());
diff --git a/core/tests/coretests/src/android/graphics/TypefaceTest.java b/core/tests/coretests/src/android/graphics/TypefaceTest.java
index 5fa8c4fbaa56..392c6b7199a5 100644
--- a/core/tests/coretests/src/android/graphics/TypefaceTest.java
+++ b/core/tests/coretests/src/android/graphics/TypefaceTest.java
@@ -23,8 +23,11 @@ import static org.junit.Assert.assertTrue;
import android.content.Context;
import android.content.res.AssetManager;
import android.content.res.Resources;
+import android.graphics.fonts.FontFamily;
import android.graphics.fonts.SystemFonts;
import android.os.SharedMemory;
+import android.text.FontConfig;
+import android.util.Pair;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.LargeTest;
@@ -195,8 +198,9 @@ public class TypefaceTest {
@Test
public void testSerialize() throws Exception {
HashMap<String, Typeface> systemFontMap = new HashMap<>();
- Typeface.initSystemDefaultTypefaces(systemFontMap, SystemFonts.getRawSystemFallbackMap(),
- SystemFonts.getAliases());
+ Pair<FontConfig.Alias[], Map<String, FontFamily[]>> res =
+ SystemFonts.initializePreinstalledFonts();
+ Typeface.initSystemDefaultTypefaces(systemFontMap, res.second, res.first);
SharedMemory sharedMemory = Typeface.serializeFontMap(systemFontMap);
Map<String, Typeface> copiedFontMap =
Typeface.deserializeFontMap(sharedMemory.mapReadOnly().order(ByteOrder.BIG_ENDIAN));
diff --git a/core/tests/coretests/src/android/text/FontFallbackSetup.java b/core/tests/coretests/src/android/text/FontFallbackSetup.java
index cc51ec3da1fd..64e6f82d82af 100644
--- a/core/tests/coretests/src/android/text/FontFallbackSetup.java
+++ b/core/tests/coretests/src/android/text/FontFallbackSetup.java
@@ -20,7 +20,6 @@ import android.annotation.NonNull;
import android.content.Context;
import android.content.res.AssetManager;
import android.graphics.Typeface;
-import android.graphics.fonts.Font;
import android.graphics.fonts.FontCustomizationParser;
import android.graphics.fonts.FontFamily;
import android.graphics.fonts.SystemFonts;
@@ -35,7 +34,6 @@ import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
-import java.util.ArrayList;
public class FontFallbackSetup implements AutoCloseable {
private final String[] mTestFontFiles;
@@ -78,11 +76,10 @@ public class FontFallbackSetup implements AutoCloseable {
}
final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
- final ArrayList<Font> availableFonts = new ArrayList<>();
final FontCustomizationParser.Result oemCustomization =
new FontCustomizationParser.Result();
final FontConfig.Alias[] aliases = SystemFonts.buildSystemFallback(testFontsXml,
- mTestFontsDir, oemCustomization, fallbackMap, availableFonts);
+ mTestFontsDir, oemCustomization, fallbackMap);
Typeface.initSystemDefaultTypefaces(mFontMap, fallbackMap, aliases);
}
diff --git a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
index 75dd7fb82f30..ff1d965c643f 100644
--- a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
+++ b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
@@ -192,8 +192,8 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl {
}
@Override
- public Future<?> scheduleCpuSyncDueToScreenStateChange(
- boolean onBattery, boolean onBatteryScreenOff) {
+ public Future<?> scheduleSyncDueToScreenStateChange(
+ int flag, boolean onBattery, boolean onBatteryScreenOff, int screenState) {
return null;
}
diff --git a/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java b/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java
new file mode 100644
index 000000000000..88295efa90b9
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.power;
+
+import static com.android.internal.power.MeasuredEnergyArray.NUMBER_SUBSYSTEMS;
+import static com.android.internal.power.MeasuredEnergyArray.SUBSYSTEM_DISPLAY;
+import static com.android.internal.power.MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_DOZE;
+import static com.android.internal.power.MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_ON;
+import static com.android.internal.power.MeasuredEnergyStats.NUMBER_ENERGY_BUCKETS;
+
+import static org.junit.Assert.assertEquals;
+
+import android.os.Parcel;
+import android.view.Display;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test class for {@link MeasuredEnergyStats}.
+ *
+ * To run the tests, use
+ * atest FrameworksCoreTests:com.android.internal.power.MeasuredEnergyStatsTest
+ */
+public class MeasuredEnergyStatsTest {
+ private MeasuredEnergyStats mStats;
+ private int[] mAllSubsystems = new int[NUMBER_SUBSYSTEMS];
+ private long[] mCurrentSubsystemEnergyUJ = new long[NUMBER_SUBSYSTEMS];
+
+ MeasuredEnergyArray mMeasuredEnergyArray = new MeasuredEnergyArray() {
+ @Override
+ public int getSubsystem(int index) {
+ return mAllSubsystems[index];
+ }
+
+ @Override
+ public long getEnergy(int index) {
+ return mCurrentSubsystemEnergyUJ[index];
+ }
+
+ @Override
+ public int size() {
+ return NUMBER_SUBSYSTEMS;
+ }
+ };
+
+ @Before
+ public void setUp() {
+ // Populate all supported subsystems indexes and arbitrary starting energy values.
+ mAllSubsystems[SUBSYSTEM_DISPLAY] = SUBSYSTEM_DISPLAY;
+ mCurrentSubsystemEnergyUJ[SUBSYSTEM_DISPLAY] = 111;
+
+ mStats = new MeasuredEnergyStats(mMeasuredEnergyArray, Display.STATE_UNKNOWN);
+ }
+
+ @Test
+ public void testReadWriteParcel() {
+ // update with some arbitrary data
+ mCurrentSubsystemEnergyUJ[SUBSYSTEM_DISPLAY] += 222;
+ mStats.update(mMeasuredEnergyArray, Display.STATE_ON, true);
+ mCurrentSubsystemEnergyUJ[SUBSYSTEM_DISPLAY] += 321;
+ mStats.update(mMeasuredEnergyArray, Display.STATE_DOZE, true);
+ mCurrentSubsystemEnergyUJ[SUBSYSTEM_DISPLAY] += 456;
+ mStats.update(mMeasuredEnergyArray, Display.STATE_OFF, true);
+
+ final Parcel parcel = Parcel.obtain();
+ mStats.writeToParcel(parcel);
+
+ parcel.setDataPosition(0);
+ MeasuredEnergyStats stats = new MeasuredEnergyStats(parcel);
+
+ for (int i = 0; i < NUMBER_ENERGY_BUCKETS; i++) {
+ assertEquals(mStats.getAccumulatedBucketEnergy(i), stats.getAccumulatedBucketEnergy(i));
+ }
+ parcel.recycle();
+ }
+
+ @Test
+ public void testReadWriteSummaryParcel() {
+ // update with some arbitrary data
+ mCurrentSubsystemEnergyUJ[SUBSYSTEM_DISPLAY] += 222;
+ mStats.update(mMeasuredEnergyArray, Display.STATE_ON, true);
+ mCurrentSubsystemEnergyUJ[SUBSYSTEM_DISPLAY] += 321;
+ mStats.update(mMeasuredEnergyArray, Display.STATE_DOZE, true);
+ mCurrentSubsystemEnergyUJ[SUBSYSTEM_DISPLAY] += 456;
+ mStats.update(mMeasuredEnergyArray, Display.STATE_OFF, true);
+
+ final Parcel parcel = Parcel.obtain();
+ MeasuredEnergyStats.writeSummaryToParcel(mStats, parcel);
+
+ parcel.setDataPosition(0);
+ MeasuredEnergyStats stats = new MeasuredEnergyStats(mMeasuredEnergyArray,
+ Display.STATE_UNKNOWN);
+ MeasuredEnergyStats.readSummaryFromParcel(stats, parcel);
+
+ for (int i = 0; i < NUMBER_ENERGY_BUCKETS; i++) {
+ assertEquals(mStats.getAccumulatedBucketEnergy(i), stats.getAccumulatedBucketEnergy(i));
+ }
+ parcel.recycle();
+ }
+
+ @Test
+ public void testDisplayStateEnergyAttribution() {
+ long expectedScreenOnEnergy = 0;
+ long expectedScreenDozeEnergy = 0;
+
+ // Display energy should be attributed to the previous screen state.
+ mStats.update(mMeasuredEnergyArray, Display.STATE_UNKNOWN, true);
+
+ incrementDisplayState(222, Display.STATE_ON, true, expectedScreenOnEnergy,
+ expectedScreenDozeEnergy);
+
+ expectedScreenOnEnergy += 321;
+ incrementDisplayState(321, Display.STATE_DOZE, true, expectedScreenOnEnergy,
+ expectedScreenDozeEnergy);
+
+ expectedScreenDozeEnergy += 456;
+ incrementDisplayState(456, Display.STATE_OFF, true, expectedScreenOnEnergy,
+ expectedScreenDozeEnergy);
+
+ incrementDisplayState(1111, Display.STATE_DOZE_SUSPEND, true, expectedScreenOnEnergy,
+ expectedScreenDozeEnergy);
+
+ expectedScreenDozeEnergy += 2345;
+ incrementDisplayState(2345, Display.STATE_ON_SUSPEND, true, expectedScreenOnEnergy,
+ expectedScreenDozeEnergy);
+
+ expectedScreenOnEnergy += 767;
+ incrementDisplayState(767, Display.STATE_VR, true, expectedScreenOnEnergy,
+ expectedScreenDozeEnergy);
+
+ expectedScreenOnEnergy += 999;
+ incrementDisplayState(999, Display.STATE_UNKNOWN, true, expectedScreenOnEnergy,
+ expectedScreenDozeEnergy);
+ }
+
+ @Test
+ public void testDisplayStateEnergyAttribution_notRunning() {
+ long expectedScreenOnEnergy = 0;
+ long expectedScreenDozeEnergy = 0;
+
+ // Display energy should be attributed to the previous screen state.
+ mStats.update(mMeasuredEnergyArray, Display.STATE_UNKNOWN, true);
+
+ incrementDisplayState(222, Display.STATE_ON, true, expectedScreenOnEnergy,
+ expectedScreenDozeEnergy);
+
+ expectedScreenOnEnergy += 321;
+ incrementDisplayState(321, Display.STATE_DOZE, true, expectedScreenOnEnergy,
+ expectedScreenDozeEnergy);
+
+ // Updates after this point should not result in energy accumulation.
+ incrementDisplayState(456, Display.STATE_OFF, false, expectedScreenOnEnergy,
+ expectedScreenDozeEnergy);
+
+ incrementDisplayState(1111, Display.STATE_DOZE_SUSPEND, false, expectedScreenOnEnergy,
+ expectedScreenDozeEnergy);
+
+ incrementDisplayState(2345, Display.STATE_ON_SUSPEND, false, expectedScreenOnEnergy,
+ expectedScreenDozeEnergy);
+
+ incrementDisplayState(767, Display.STATE_VR, false, expectedScreenOnEnergy,
+ expectedScreenDozeEnergy);
+
+ // Resume energy accumulation.
+ expectedScreenOnEnergy += 999;
+ incrementDisplayState(999, Display.STATE_UNKNOWN, true, expectedScreenOnEnergy,
+ expectedScreenDozeEnergy);
+ }
+
+ @Test
+ public void testReset() {
+ // update with some arbitrary data.
+ mCurrentSubsystemEnergyUJ[SUBSYSTEM_DISPLAY] += 222;
+ mStats.update(mMeasuredEnergyArray, Display.STATE_ON, true);
+ mCurrentSubsystemEnergyUJ[SUBSYSTEM_DISPLAY] += 321;
+ mStats.update(mMeasuredEnergyArray, Display.STATE_DOZE, true);
+ mCurrentSubsystemEnergyUJ[SUBSYSTEM_DISPLAY] += 456;
+ mStats.update(mMeasuredEnergyArray, Display.STATE_OFF, true);
+
+ mStats.reset();
+ // All energy should be reset to 0
+ for (int i = 0; i < NUMBER_ENERGY_BUCKETS; i++) {
+ assertEquals(mStats.getAccumulatedBucketEnergy(i), 0);
+ }
+
+ // Increment all subsystem energy by some arbitrary amount and update
+ for (int i = 0; i < NUMBER_SUBSYSTEMS; i++) {
+ mCurrentSubsystemEnergyUJ[i] += 100 * i;
+ }
+ mStats.update(mMeasuredEnergyArray, Display.STATE_OFF, true);
+
+ // All energy should still be 0 after the first post-reset update.
+ for (int i = 0; i < NUMBER_ENERGY_BUCKETS; i++) {
+ assertEquals(mStats.getAccumulatedBucketEnergy(i), 0);
+ }
+
+ // Energy accumulation should continue like normal.
+ long expectedScreenOnEnergy = 0;
+ long expectedScreenDozeEnergy = 0;
+ incrementDisplayState(222, Display.STATE_ON, true, expectedScreenOnEnergy,
+ expectedScreenDozeEnergy);
+
+ expectedScreenOnEnergy += 321;
+ incrementDisplayState(321, Display.STATE_DOZE, true, expectedScreenOnEnergy,
+ expectedScreenDozeEnergy);
+
+ expectedScreenDozeEnergy += 456;
+ incrementDisplayState(456, Display.STATE_OFF, true, expectedScreenOnEnergy,
+ expectedScreenDozeEnergy);
+ }
+
+ @Test
+ public void testHasSubsystem() {
+ for (int i = 0; i < NUMBER_SUBSYSTEMS; i++) {
+ assertEquals(mStats.hasSubsystem(i), true);
+ }
+ }
+
+ @Test
+ public void testHasSubsystem_unavailable() {
+ // Setup MeasuredEnergyStats with not available subsystems.
+ int[] subsystems = new int[0];
+ long[] energies = new long[0];
+ MeasuredEnergyArray measuredEnergyArray = new MeasuredEnergyArray() {
+ @Override
+ public int getSubsystem(int index) {
+ return subsystems[index];
+ }
+
+ @Override
+ public long getEnergy(int index) {
+ return energies[index];
+ }
+
+ @Override
+ public int size() {
+ return 0;
+ }
+ };
+ MeasuredEnergyStats stats = new MeasuredEnergyStats(measuredEnergyArray,
+ Display.STATE_UNKNOWN);
+
+ for (int i = 0; i < NUMBER_SUBSYSTEMS; i++) {
+ assertEquals(stats.hasSubsystem(i), false);
+ }
+
+ stats.reset();
+ // a reset should not change the state of an unavailable subsystem.
+ for (int i = 0; i < NUMBER_SUBSYSTEMS; i++) {
+ assertEquals(stats.hasSubsystem(i), false);
+ }
+ }
+
+ private void incrementDisplayState(long deltaEnergy, int nextState, boolean accumulate,
+ long expectScreenEnergy, long expectedDozeEnergy) {
+ mCurrentSubsystemEnergyUJ[SUBSYSTEM_DISPLAY] += deltaEnergy;
+ mStats.update(mMeasuredEnergyArray, nextState, accumulate);
+ assertEquals(expectScreenEnergy,
+ mStats.getAccumulatedBucketEnergy(ENERGY_BUCKET_SCREEN_ON));
+ assertEquals(expectedDozeEnergy,
+ mStats.getAccumulatedBucketEnergy(ENERGY_BUCKET_SCREEN_DOZE));
+ }
+}
diff --git a/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerStatsData.java b/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerStatsData.java
index 099ee22b12e4..7aeb86ae0cb1 100644
--- a/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerStatsData.java
+++ b/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerStatsData.java
@@ -17,6 +17,7 @@
package com.android.frameworks.core.powerstatsviewer;
import android.content.Context;
+import android.os.BatteryStats;
import android.os.Process;
import com.android.internal.os.BatterySipper;
@@ -32,6 +33,15 @@ public class PowerStatsData {
private static final String[] PACKAGES_SYSTEM = {PACKAGE_MEDIA_PROVIDER,
PACKAGE_CALENDAR_PROVIDER, PACKAGE_SYSTEMUI};
+ // Temporary placeholder voltage for converting energy to charge
+ // TODO: remove this when b/173765509 is resolved
+ private static final double MOCK_NOMINAL_VOLTAGE = 3.7;
+
+ // Unit conversion:
+ // mAh = uWs * (1/1000)(milli/micro) * (1/Voltage) * (1/3600)(hours/second)
+ private static final double UJ_2_MAH =
+ (1.0 / 1000) * (1.0 / MOCK_NOMINAL_VOLTAGE) * (1.0 / 3600);
+
enum EntryType {
POWER,
DURATION,
@@ -50,6 +60,7 @@ public class PowerStatsData {
public PowerStatsData(Context context, BatteryStatsHelper batteryStatsHelper,
String powerConsumerId) {
List<BatterySipper> usageList = batteryStatsHelper.getUsageList();
+ BatteryStats batteryStats = batteryStatsHelper.getStats();
double totalPowerMah = 0;
double totalSmearedPowerMah = 0;
@@ -125,6 +136,8 @@ public class PowerStatsData {
totalVideoTimeMs += sipper.videoTimeMs;
}
+ long totalScreenMeasuredEnergyUJ = batteryStats.getScreenOnEnergy();
+
if (requestedPowerConsumer == null) {
mPowerConsumerInfo = null;
return;
@@ -135,10 +148,18 @@ public class PowerStatsData {
addEntry("Total power", EntryType.POWER,
requestedPowerConsumer.totalSmearedPowerMah, totalSmearedPowerMah);
+ maybeAddMeasuredEnergyEntry(requestedPowerConsumer.drainType, batteryStats);
+
addEntry("... excluding system", EntryType.POWER,
requestedPowerConsumer.totalSmearedPowerMah, totalPowerExcludeSystemMah);
addEntry("Screen, smeared", EntryType.POWER,
requestedPowerConsumer.screenPowerMah, totalScreenPower);
+ if (totalScreenMeasuredEnergyUJ != BatteryStats.ENERGY_DATA_UNAVAILABLE) {
+ final double measuredCharge = UJ_2_MAH * totalScreenMeasuredEnergyUJ;
+ final double ratio = measuredCharge / totalScreenPower;
+ addEntry("Screen, smeared (PowerStatsHal adjusted)", EntryType.POWER,
+ requestedPowerConsumer.screenPowerMah * ratio, measuredCharge);
+ }
addEntry("Other, smeared", EntryType.POWER,
requestedPowerConsumer.proportionalSmearMah, totalProportionalSmearMah);
addEntry("Excluding smeared", EntryType.POWER,
@@ -218,6 +239,28 @@ public class PowerStatsData {
mEntries.add(entry);
}
+ private void maybeAddMeasuredEnergyEntry(BatterySipper.DrainType drainType,
+ BatteryStats batteryStats) {
+ switch (drainType) {
+ case AMBIENT_DISPLAY:
+ final long totalDozeMeasuredEnergyUJ = batteryStats.getScreenDozeEnergy();
+ if (totalDozeMeasuredEnergyUJ != BatteryStats.ENERGY_DATA_UNAVAILABLE) {
+ final double measuredCharge = UJ_2_MAH * totalDozeMeasuredEnergyUJ;
+ addEntry("Measured ambient display power", EntryType.POWER, measuredCharge,
+ measuredCharge);
+ }
+ break;
+ case SCREEN:
+ final long totalScreenMeasuredEnergyUJ = batteryStats.getScreenOnEnergy();
+ if (totalScreenMeasuredEnergyUJ != BatteryStats.ENERGY_DATA_UNAVAILABLE) {
+ final double measuredCharge = UJ_2_MAH * totalScreenMeasuredEnergyUJ;
+ addEntry("Measured screen power", EntryType.POWER, measuredCharge,
+ measuredCharge);
+ }
+ break;
+ }
+ }
+
public PowerConsumerInfoHelper.PowerConsumerInfo getPowerConsumerInfo() {
return mPowerConsumerInfo;
}
diff --git a/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerStatsViewerActivity.java b/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerStatsViewerActivity.java
index 78f2b9135d0c..05679101f86a 100644
--- a/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerStatsViewerActivity.java
+++ b/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerStatsViewerActivity.java
@@ -29,6 +29,7 @@ import android.widget.ImageView;
import android.widget.TextView;
import androidx.activity.ComponentActivity;
+import androidx.activity.result.ActivityResultLauncher;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.loader.app.LoaderManager;
@@ -60,6 +61,8 @@ public class PowerStatsViewerActivity extends ComponentActivity {
private RecyclerView mPowerStatsDataView;
private View mLoadingView;
private View mEmptyView;
+ private ActivityResultLauncher<Void> mStartAppPicker = registerForActivityResult(
+ PowerConsumerPickerActivity.CONTRACT, this::onApplicationSelected);
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
@@ -105,8 +108,7 @@ public class PowerStatsViewerActivity extends ComponentActivity {
}
private void startAppPicker() {
- registerForActivityResult(PowerConsumerPickerActivity.CONTRACT, this::onApplicationSelected)
- .launch(null);
+ mStartAppPicker.launch(null);
}
private void onApplicationSelected(String powerConsumerId) {
diff --git a/data/etc/com.android.provision.xml b/data/etc/com.android.provision.xml
index 05404ef73732..d2ea0ec085d3 100644
--- a/data/etc/com.android.provision.xml
+++ b/data/etc/com.android.provision.xml
@@ -17,5 +17,7 @@
<permissions>
<privapp-permissions package="com.android.provision">
<permission name="android.permission.WRITE_SECURE_SETTINGS"/>
+ <permissionn ame="android.permission.DISPATCH_PROVISIONING_MESSAGE"/>
+ <permission name="android.permission.MASTER_CLEAR"/>
</privapp-permissions>
</permissions>
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 52da707565d7..10310237f89b 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -961,6 +961,12 @@
"group": "WM_DEBUG_WINDOW_ORGANIZER",
"at": "com\/android\/server\/wm\/TaskOrganizerController.java"
},
+ "-948446688": {
+ "message": "Create TaskDisplayArea uid=%d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_ORGANIZER",
+ "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
+ },
"-937498525": {
"message": "Executing finish of failed to pause activity: %s",
"level": "VERBOSE",
@@ -1273,6 +1279,12 @@
"group": "WM_DEBUG_STATES",
"at": "com\/android\/server\/wm\/Task.java"
},
+ "-597091183": {
+ "message": "Delete TaskDisplayArea uid=%d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_ORGANIZER",
+ "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
+ },
"-593535526": {
"message": "Binding proc %s with config %s",
"level": "VERBOSE",
@@ -1495,12 +1507,6 @@
"group": "WM_DEBUG_APP_TRANSITIONS",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
- "-371630969": {
- "message": "New wallpaper target=%s, oldWallpaper=%s, openingApps=%s, closingApps=%s",
- "level": "VERBOSE",
- "group": "WM_DEBUG_APP_TRANSITIONS",
- "at": "com\/android\/server\/wm\/AppTransitionController.java"
- },
"-354571697": {
"message": "Existence Changed in transition %d: %s",
"level": "VERBOSE",
@@ -2101,12 +2107,6 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
- "355940361": {
- "message": "Config is destroying non-running %s",
- "level": "VERBOSE",
- "group": "WM_DEBUG_CONFIGURATION",
- "at": "com\/android\/server\/wm\/ActivityRecord.java"
- },
"371173718": {
"message": "finishSync cancel=%b for %s",
"level": "VERBOSE",
diff --git a/graphics/java/android/graphics/HardwareRenderer.java b/graphics/java/android/graphics/HardwareRenderer.java
index a7f2739153e1..cb4dd9e8cacd 100644
--- a/graphics/java/android/graphics/HardwareRenderer.java
+++ b/graphics/java/android/graphics/HardwareRenderer.java
@@ -1163,7 +1163,7 @@ public class HardwareRenderer {
// heuristic we don't need to be always 100% correct.
Mode activeMode = display.getMode();
nInitDisplayInfo(activeMode.getPhysicalWidth(), activeMode.getPhysicalHeight(),
- activeMode.getRefreshRate(), maxRefreshRate,
+ display.getRefreshRate(), maxRefreshRate,
wideColorDataspace.mNativeDataspace, display.getAppVsyncOffsetNanos(),
display.getPresentationDeadlineNanos());
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 712349aaee57..36ef0a48fa20 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -44,6 +44,7 @@ import android.text.FontConfig;
import android.util.Base64;
import android.util.LongSparseArray;
import android.util.LruCache;
+import android.util.Pair;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
@@ -1321,8 +1322,9 @@ public class Typeface {
/** @hide */
public static void loadPreinstalledSystemFontMap() {
final HashMap<String, Typeface> systemFontMap = new HashMap<>();
- initSystemDefaultTypefaces(systemFontMap, SystemFonts.getRawSystemFallbackMap(),
- SystemFonts.getAliases());
+ Pair<FontConfig.Alias[], Map<String, FontFamily[]>> pair =
+ SystemFonts.initializePreinstalledFonts();
+ initSystemDefaultTypefaces(systemFontMap, pair.second, pair.first);
setSystemFontMap(systemFontMap);
}
diff --git a/graphics/java/android/graphics/fonts/SystemFonts.java b/graphics/java/android/graphics/fonts/SystemFonts.java
index 95c470634518..3635adc3ce39 100644
--- a/graphics/java/android/graphics/fonts/SystemFonts.java
+++ b/graphics/java/android/graphics/fonts/SystemFonts.java
@@ -22,7 +22,9 @@ import android.graphics.FontListParser;
import android.text.FontConfig;
import android.util.ArrayMap;
import android.util.Log;
+import android.util.Pair;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
@@ -51,9 +53,9 @@ public final class SystemFonts {
private SystemFonts() {} // Do not instansiate.
- private static final Map<String, FontFamily[]> sSystemFallbackMap;
- private static final FontConfig.Alias[] sAliases;
- private static final List<Font> sAvailableFonts;
+ private static final Object LOCK = new Object();
+ private static @GuardedBy("sLock") Set<Font> sAvailableFonts;
+ private static @GuardedBy("sLock") Map<String, FontFamily[]> sFamilyMap;
/**
* Returns all available font files in the system.
@@ -61,29 +63,24 @@ public final class SystemFonts {
* @return a set of system fonts
*/
public static @NonNull Set<Font> getAvailableFonts() {
- HashSet<Font> set = new HashSet<>();
- set.addAll(sAvailableFonts);
- return set;
- }
+ synchronized (LOCK) {
+ if (sAvailableFonts != null) {
+ return sAvailableFonts;
+ }
- /**
- * Returns raw system fallback map.
- *
- * This method is intended to be used only by Typeface static initializer.
- * @hide
- */
- public static @NonNull Map<String, FontFamily[]> getRawSystemFallbackMap() {
- return sSystemFallbackMap;
- }
+ Set<Font> set = new HashSet<>();
- /**
- * Returns a list of aliases.
- *
- * This method is intended to be used only by Typeface static initializer.
- * @hide
- */
- public static @NonNull FontConfig.Alias[] getAliases() {
- return sAliases;
+ for (FontFamily[] items : sFamilyMap.values()) {
+ for (FontFamily family : items) {
+ for (int i = 0; i < family.getSize(); ++i) {
+ set.add(family.getFont(i));
+ }
+ }
+ }
+
+ sAvailableFonts = Collections.unmodifiableSet(set);
+ return sAvailableFonts;
+ }
}
private static @Nullable ByteBuffer mmap(@NonNull String fullPath) {
@@ -98,8 +95,7 @@ public final class SystemFonts {
private static void pushFamilyToFallback(@NonNull FontConfig.Family xmlFamily,
@NonNull ArrayMap<String, ArrayList<FontFamily>> fallbackMap,
- @NonNull Map<String, ByteBuffer> cache,
- @NonNull ArrayList<Font> availableFonts) {
+ @NonNull Map<String, ByteBuffer> cache) {
final String languageTags = xmlFamily.getLanguages();
final int variant = xmlFamily.getVariant();
@@ -123,7 +119,7 @@ public final class SystemFonts {
}
final FontFamily defaultFamily = defaultFonts.isEmpty() ? null : createFontFamily(
- xmlFamily.getName(), defaultFonts, languageTags, variant, cache, availableFonts);
+ xmlFamily.getName(), defaultFonts, languageTags, variant, cache);
// Insert family into fallback map.
for (int i = 0; i < fallbackMap.size(); i++) {
@@ -135,8 +131,7 @@ public final class SystemFonts {
}
} else {
final FontFamily family = createFontFamily(
- xmlFamily.getName(), fallback, languageTags, variant, cache,
- availableFonts);
+ xmlFamily.getName(), fallback, languageTags, variant, cache);
if (family != null) {
fallbackMap.valueAt(i).add(family);
} else if (defaultFamily != null) {
@@ -152,8 +147,7 @@ public final class SystemFonts {
@NonNull List<FontConfig.Font> fonts,
@NonNull String languageTags,
@FontConfig.Family.Variant int variant,
- @NonNull Map<String, ByteBuffer> cache,
- @NonNull ArrayList<Font> availableFonts) {
+ @NonNull Map<String, ByteBuffer> cache) {
if (fonts.size() == 0) {
return null;
}
@@ -187,7 +181,6 @@ public final class SystemFonts {
throw new RuntimeException(e); // Never reaches here
}
- availableFonts.add(font);
if (b == null) {
b = new FontFamily.Builder(font);
} else {
@@ -199,12 +192,11 @@ public final class SystemFonts {
private static void appendNamedFamily(@NonNull FontConfig.Family xmlFamily,
@NonNull HashMap<String, ByteBuffer> bufferCache,
- @NonNull ArrayMap<String, ArrayList<FontFamily>> fallbackListMap,
- @NonNull ArrayList<Font> availableFonts) {
+ @NonNull ArrayMap<String, ArrayList<FontFamily>> fallbackListMap) {
final String familyName = xmlFamily.getName();
final FontFamily family = createFontFamily(
familyName, Arrays.asList(xmlFamily.getFonts()),
- xmlFamily.getLanguages(), xmlFamily.getVariant(), bufferCache, availableFonts);
+ xmlFamily.getLanguages(), xmlFamily.getVariant(), bufferCache);
if (family == null) {
return;
}
@@ -227,8 +219,7 @@ public final class SystemFonts {
public static FontConfig.Alias[] buildSystemFallback(@NonNull String xmlPath,
@NonNull String fontDir,
@NonNull FontCustomizationParser.Result oemCustomization,
- @NonNull ArrayMap<String, FontFamily[]> fallbackMap,
- @NonNull ArrayList<Font> availableFonts) {
+ @NonNull Map<String, FontFamily[]> fallbackMap) {
try {
final FileInputStream fontsIn = new FileInputStream(xmlPath);
final FontConfig fontConfig = FontListParser.parse(fontsIn, fontDir);
@@ -243,12 +234,12 @@ public final class SystemFonts {
if (familyName == null) {
continue;
}
- appendNamedFamily(xmlFamily, bufferCache, fallbackListMap, availableFonts);
+ appendNamedFamily(xmlFamily, bufferCache, fallbackListMap);
}
for (int i = 0; i < oemCustomization.mAdditionalNamedFamilies.size(); ++i) {
appendNamedFamily(oemCustomization.mAdditionalNamedFamilies.get(i),
- bufferCache, fallbackListMap, availableFonts);
+ bufferCache, fallbackListMap);
}
// Then, add fallback fonts to the each fallback map.
@@ -257,7 +248,7 @@ public final class SystemFonts {
// The first family (usually the sans-serif family) is always placed immediately
// after the primary family in the fallback.
if (i == 0 || xmlFamily.getName() == null) {
- pushFamilyToFallback(xmlFamily, fallbackListMap, bufferCache, availableFonts);
+ pushFamilyToFallback(xmlFamily, fallbackListMap, bufferCache);
}
}
@@ -292,14 +283,17 @@ public final class SystemFonts {
}
}
- static {
- final ArrayMap<String, FontFamily[]> systemFallbackMap = new ArrayMap<>();
- final ArrayList<Font> availableFonts = new ArrayList<>();
+ /** @hide */
+ public static @NonNull Pair<FontConfig.Alias[], Map<String, FontFamily[]>>
+ initializePreinstalledFonts() {
final FontCustomizationParser.Result oemCustomization =
readFontCustomization("/product/etc/fonts_customization.xml", "/product/fonts/");
- sAliases = buildSystemFallback("/system/etc/fonts.xml", "/system/fonts/",
- oemCustomization, systemFallbackMap, availableFonts);
- sSystemFallbackMap = Collections.unmodifiableMap(systemFallbackMap);
- sAvailableFonts = Collections.unmodifiableList(availableFonts);
+ Map<String, FontFamily[]> map = new ArrayMap<>();
+ FontConfig.Alias[] aliases = buildSystemFallback("/system/etc/fonts.xml", "/system/fonts/",
+ oemCustomization, map);
+ synchronized (LOCK) {
+ sFamilyMap = map;
+ }
+ return new Pair(aliases, map);
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt
index 3c222e7d8b56..bbf5afcff67a 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt
@@ -31,6 +31,10 @@ val TEST_APP_PIP_ACTIVITY_COMPONENT_NAME: ComponentName = ComponentName.createRe
TEST_APP_PACKAGE_NAME, ".PipActivity")
const val TEST_APP_PIP_ACTIVITY_LABEL = "PipApp"
const val TEST_APP_PIP_ACTIVITY_WINDOW_NAME = "PipActivity"
+const val TEST_APP_PIP_MENU_ACTION_NO_OP = "No-Op"
+const val TEST_APP_PIP_MENU_ACTION_ON = "On"
+const val TEST_APP_PIP_MENU_ACTION_OFF = "Off"
+const val TEST_APP_PIP_MENU_ACTION_CLEAR = "Clear"
// Test App > Ime Activity
val TEST_APP_IME_ACTIVITY_COMPONENT_NAME: ComponentName = ComponentName.createRelative(
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
index 532b3de6c99e..e85ba9ef6da2 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
@@ -70,6 +70,12 @@ class PipAppHelper(
startButton.click()
}
+ fun checkWithCustomActionsCheckbox() = uiDevice
+ .findObject(By.res(packageName, "with_custom_actions"))
+ ?.takeIf { it.isCheckable }
+ ?.apply { if (!isChecked) click() }
+ ?: error("'With custom actions' checkbox not found")
+
fun pauseMedia() = mediaController?.transportControls?.pause()
?: error("No active media session found")
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt
index 871732cf7460..4cb6447f7d7e 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt
@@ -20,7 +20,12 @@ import android.graphics.Rect
import androidx.test.filters.RequiresDevice
import androidx.test.uiautomator.UiObject2
import com.android.wm.shell.flicker.SYSTEM_UI_PACKAGE_NAME
+import com.android.wm.shell.flicker.TEST_APP_PIP_MENU_ACTION_CLEAR
+import com.android.wm.shell.flicker.TEST_APP_PIP_MENU_ACTION_NO_OP
+import com.android.wm.shell.flicker.TEST_APP_PIP_MENU_ACTION_OFF
+import com.android.wm.shell.flicker.TEST_APP_PIP_MENU_ACTION_ON
import com.android.wm.shell.flicker.wait
+import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
@@ -128,6 +133,7 @@ class TvPipMenuTests : TvPipTestBase() {
testApp.clickStartMediaSessionButton()
enterPip_openMenu_assertShown()
+ assertFullscreenAndCloseButtonsAreShown()
// PiP menu should contain the Pause button
val pauseButton = uiDevice.findTvPipMenuElementWithDescription(pauseButtonDescription)
@@ -137,6 +143,7 @@ class TvPipMenuTests : TvPipTestBase() {
// When we pause media, the button should change from Pause to Play
pauseButton.click()
+ assertFullscreenAndCloseButtonsAreShown()
// PiP menu should contain the Play button now
uiDevice.waitForTvPipMenuElementWithDescription(playButtonDescription)
?: fail("\"Play\" button should be shown in Pip menu if there is an active " +
@@ -145,10 +152,99 @@ class TvPipMenuTests : TvPipTestBase() {
testApp.closePipWindow()
}
+ @Test
+ fun pipMenu_withCustomActions() {
+ // Enter PiP with custom actions.
+ testApp.checkWithCustomActionsCheckbox()
+ enterPip_openMenu_assertShown()
+
+ // PiP menu should contain "No-Op", "Off" and "Clear" buttons...
+ uiDevice.findTvPipMenuElementWithDescription(TEST_APP_PIP_MENU_ACTION_NO_OP)
+ ?: fail("\"No-Op\" button should be shown in Pip menu")
+ val offButton = uiDevice.findTvPipMenuElementWithDescription(TEST_APP_PIP_MENU_ACTION_OFF)
+ ?: fail("\"Off\" button should be shown in Pip menu")
+ uiDevice.findTvPipMenuElementWithDescription(TEST_APP_PIP_MENU_ACTION_CLEAR)
+ ?: fail("\"Clear\" button should be shown in Pip menu")
+ // ... and should also contain the "Full screen" and "Close" buttons.
+ assertFullscreenAndCloseButtonsAreShown()
+
+ offButton.click()
+ // Invoking the "Off" action should replace it with the "On" action/button and should
+ // remove the "No-Op" action/button. "Clear" action/button should remain in the menu ...
+ uiDevice.waitForTvPipMenuElementWithDescription(TEST_APP_PIP_MENU_ACTION_ON)
+ ?: fail("\"On\" button should be shown in Pip for a corresponding custom action")
+ assertNull("\"No-Op\" button should not be shown in Pip menu",
+ uiDevice.findTvPipMenuElementWithDescription(TEST_APP_PIP_MENU_ACTION_NO_OP))
+ val clearButton =
+ uiDevice.findTvPipMenuElementWithDescription(TEST_APP_PIP_MENU_ACTION_CLEAR)
+ ?: fail("\"Clear\" button should be shown in Pip menu")
+ // ... as well as the "Full screen" and "Close" buttons.
+ assertFullscreenAndCloseButtonsAreShown()
+
+ clearButton.click()
+ // Invoking the "Clear" action should remove all the custom actions and their corresponding
+ // buttons, ...
+ uiDevice.waitUntilTvPipMenuElementWithDescriptionIsGone(TEST_APP_PIP_MENU_ACTION_ON)?.also {
+ isGone -> if (!isGone) fail("\"On\" button should not be shown in Pip menu")
+ }
+ assertNull("\"Off\" button should not be shown in Pip menu",
+ uiDevice.findTvPipMenuElementWithDescription(TEST_APP_PIP_MENU_ACTION_OFF))
+ assertNull("\"Clear\" button should not be shown in Pip menu",
+ uiDevice.findTvPipMenuElementWithDescription(TEST_APP_PIP_MENU_ACTION_CLEAR))
+ assertNull("\"No-Op\" button should not be shown in Pip menu",
+ uiDevice.findTvPipMenuElementWithDescription(TEST_APP_PIP_MENU_ACTION_NO_OP))
+ // ... but the menu should still contain the "Full screen" and "Close" buttons.
+ assertFullscreenAndCloseButtonsAreShown()
+
+ testApp.closePipWindow()
+ }
+
+ @Test
+ fun pipMenu_customActions_override_mediaControls() {
+ // Start media session before entering PiP with custom actions.
+ testApp.clickStartMediaSessionButton()
+ testApp.checkWithCustomActionsCheckbox()
+ enterPip_openMenu_assertShown()
+
+ // PiP menu should contain "No-Op", "Off" and "Clear" buttons for the custom actions...
+ uiDevice.findTvPipMenuElementWithDescription(TEST_APP_PIP_MENU_ACTION_NO_OP)
+ ?: fail("\"No-Op\" button should be shown in Pip menu")
+ uiDevice.findTvPipMenuElementWithDescription(TEST_APP_PIP_MENU_ACTION_OFF)
+ ?: fail("\"Off\" button should be shown in Pip menu")
+ val clearButton =
+ uiDevice.findTvPipMenuElementWithDescription(TEST_APP_PIP_MENU_ACTION_CLEAR)
+ ?: fail("\"Clear\" button should be shown in Pip menu")
+ // ... should also contain the "Full screen" and "Close" buttons, ...
+ assertFullscreenAndCloseButtonsAreShown()
+ // ... but should not contain media buttons.
+ assertNull("\"Play\" button should not be shown in menu when there are custom actions",
+ uiDevice.findTvPipMenuElementWithDescription(playButtonDescription))
+ assertNull("\"Pause\" button should not be shown in menu when there are custom actions",
+ uiDevice.findTvPipMenuElementWithDescription(pauseButtonDescription))
+
+ clearButton.click()
+ // Invoking the "Clear" action should remove all the custom actions, which should bring up
+ // media buttons...
+ uiDevice.waitForTvPipMenuElementWithDescription(pauseButtonDescription)
+ ?: fail("\"Pause\" button should be shown in Pip menu if there is an active " +
+ "playing media session.")
+ // ... while the "Full screen" and "Close" buttons should remain in the menu.
+ assertFullscreenAndCloseButtonsAreShown()
+
+ testApp.closePipWindow()
+ }
+
private fun enterPip_openMenu_assertShown(): UiObject2 {
testApp.clickEnterPipButton()
// Pressing the Window key should bring up Pip menu
uiDevice.pressWindowKey()
return uiDevice.waitForTvPipMenu() ?: fail("Pip menu should have been shown")
}
+
+ private fun assertFullscreenAndCloseButtonsAreShown() {
+ uiDevice.findTvPipMenuCloseButton()
+ ?: fail("\"Close PIP\" button should be shown in Pip menu")
+ uiDevice.findTvPipMenuFullscreenButton()
+ ?: fail("\"Full screen\" button should be shown in Pip menu")
+ }
} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvUtils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvUtils.kt
index 8db8bc67da14..0732794903b7 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvUtils.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvUtils.kt
@@ -58,6 +58,9 @@ fun UiDevice.waitForTvPipMenuElementWithDescription(desc: String): UiObject2? {
?.findObject(buttonSelector)
}
+fun UiDevice.waitUntilTvPipMenuElementWithDescriptionIsGone(desc: String): Boolean? =
+ wait(Until.gone(By.copy(tvPipMenuSelector).hasDescendant(By.desc(desc))), WAIT_TIME_MS)
+
fun UiObject2.isFullscreen(uiDevice: UiDevice): Boolean = visibleBounds.run {
height() == uiDevice.displayHeight && width() == uiDevice.displayWidth
} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_pip.xml b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_pip.xml
index b4a4c165cc7b..e5d2f82080a2 100644
--- a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_pip.xml
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_pip.xml
@@ -28,6 +28,12 @@
android:text="Enter PIP"
android:onClick="enterPip"/>
+ <CheckBox
+ android:id="@+id/with_custom_actions"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="With custom actions"/>
+
<RadioGroup
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/PipActivity.java b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/PipActivity.java
index d2fcd0d31558..909219583bf7 100644
--- a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/PipActivity.java
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/PipActivity.java
@@ -25,7 +25,15 @@ import static android.media.session.PlaybackState.STATE_PLAYING;
import static android.media.session.PlaybackState.STATE_STOPPED;
import android.app.Activity;
+import android.app.PendingIntent;
import android.app.PictureInPictureParams;
+import android.app.RemoteAction;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Configuration;
+import android.graphics.drawable.Icon;
import android.media.MediaMetadata;
import android.media.session.MediaSession;
import android.media.session.PlaybackState;
@@ -34,6 +42,12 @@ import android.util.Rational;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
+import android.widget.CheckBox;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
public class PipActivity extends Activity {
/**
@@ -52,7 +66,19 @@ public class PipActivity extends Activity {
private static final Rational RATIO_WIDE = new Rational(2, 1);
private static final Rational RATIO_TALL = new Rational(1, 2);
- private PictureInPictureParams.Builder mPipParamsBuilder;
+ private static final String PIP_ACTION_NO_OP = "No-Op";
+ private static final String PIP_ACTION_OFF = "Off";
+ private static final String PIP_ACTION_ON = "On";
+ private static final String PIP_ACTION_CLEAR = "Clear";
+ private static final String ACTION_NO_OP = "com.android.wm.shell.flicker.testapp.NO_OP";
+ private static final String ACTION_SWITCH_OFF =
+ "com.android.wm.shell.flicker.testapp.SWITCH_OFF";
+ private static final String ACTION_SWITCH_ON = "com.android.wm.shell.flicker.testapp.SWITCH_ON";
+ private static final String ACTION_CLEAR = "com.android.wm.shell.flicker.testapp.CLEAR";
+
+ private final PictureInPictureParams.Builder mPipParamsBuilder =
+ new PictureInPictureParams.Builder()
+ .setAspectRatio(RATIO_DEFAULT);
private MediaSession mMediaSession;
private final PlaybackState.Builder mPlaybackStateBuilder = new PlaybackState.Builder()
.setActions(ACTION_PLAY | ACTION_PAUSE | ACTION_STOP)
@@ -60,6 +86,30 @@ public class PipActivity extends Activity {
private PlaybackState mPlaybackState = mPlaybackStateBuilder.build();
private final MediaMetadata.Builder mMediaMetadataBuilder = new MediaMetadata.Builder();
+ private final List<RemoteAction> mSwitchOffActions = new ArrayList<>();
+ private final List<RemoteAction> mSwitchOnActions = new ArrayList<>();
+ private final BroadcastReceiver mCustomActionReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ switch (intent.getAction()) {
+ case ACTION_SWITCH_ON:
+ mPipParamsBuilder.setActions(mSwitchOnActions);
+ break;
+ case ACTION_SWITCH_OFF:
+ mPipParamsBuilder.setActions(mSwitchOffActions);
+ break;
+ case ACTION_CLEAR:
+ mPipParamsBuilder.setActions(Collections.emptyList());
+ break;
+ case ACTION_NO_OP:
+ default:
+ return;
+ }
+ setPictureInPictureParams(mPipParamsBuilder.build());
+ }
+ };
+ private boolean mIsReceiverRegistered = false;
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -72,9 +122,6 @@ public class PipActivity extends Activity {
setContentView(R.layout.activity_pip);
- mPipParamsBuilder = new PictureInPictureParams.Builder()
- .setAspectRatio(RATIO_DEFAULT);
-
findViewById(R.id.media_session_start)
.setOnClickListener(v -> updateMediaSessionState(STATE_PLAYING));
findViewById(R.id.media_session_stop)
@@ -98,9 +145,63 @@ public class PipActivity extends Activity {
updateMediaSessionState(STATE_STOPPED);
}
});
+
+ // Build two sets of the custom actions. We'll replace one with the other when 'On'/'Off'
+ // action is invoked.
+ // The first set consists of 3 actions: 1) Off; 2) No-Op; 3) Clear.
+ // The second set consists of 2 actions: 1) On; 2) Clear.
+ // Upon invocation 'Clear' action clear-off all the custom actions, including itself.
+ final Icon icon = Icon.createWithResource(this, android.R.drawable.ic_menu_help);
+ final RemoteAction noOpAction = buildRemoteAction(icon, PIP_ACTION_NO_OP, ACTION_NO_OP);
+ final RemoteAction switchOnAction =
+ buildRemoteAction(icon, PIP_ACTION_ON, ACTION_SWITCH_ON);
+ final RemoteAction switchOffAction =
+ buildRemoteAction(icon, PIP_ACTION_OFF, ACTION_SWITCH_OFF);
+ final RemoteAction clearAllAction = buildRemoteAction(icon, PIP_ACTION_CLEAR, ACTION_CLEAR);
+ mSwitchOffActions.addAll(Arrays.asList(switchOnAction, clearAllAction));
+ mSwitchOnActions.addAll(Arrays.asList(noOpAction, switchOffAction, clearAllAction));
+ }
+
+ @Override
+ protected void onDestroy() {
+ if (mIsReceiverRegistered) {
+ unregisterReceiver(mCustomActionReceiver);
+ mIsReceiverRegistered = false;
+ }
+ super.onDestroy();
+ }
+
+ @Override
+ public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode,
+ Configuration newConfig) {
+ if (isInPictureInPictureMode && !mIsReceiverRegistered) {
+ final IntentFilter filter = new IntentFilter();
+ filter.addAction(ACTION_NO_OP);
+ filter.addAction(ACTION_SWITCH_ON);
+ filter.addAction(ACTION_SWITCH_OFF);
+ filter.addAction(ACTION_CLEAR);
+ registerReceiver(mCustomActionReceiver, filter);
+
+ mIsReceiverRegistered = true;
+ } else if (!isInPictureInPictureMode && mIsReceiverRegistered) {
+ unregisterReceiver(mCustomActionReceiver);
+
+ mIsReceiverRegistered = false;
+ }
+ }
+
+ private RemoteAction buildRemoteAction(Icon icon, String label, String action) {
+ final Intent intent = new Intent(action);
+ final PendingIntent pendingIntent =
+ PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
+ return new RemoteAction(icon, label, label, pendingIntent);
}
public void enterPip(View v) {
+ final boolean withCustomActions =
+ ((CheckBox) findViewById(R.id.with_custom_actions)).isChecked();
+ mPipParamsBuilder.setActions(
+ withCustomActions ? mSwitchOnActions : Collections.emptyList());
enterPictureInPictureMode(mPipParamsBuilder.build());
}
diff --git a/media/java/android/media/Rating.java b/media/java/android/media/Rating.java
index be752583eae5..4da23a1319af 100644
--- a/media/java/android/media/Rating.java
+++ b/media/java/android/media/Rating.java
@@ -206,11 +206,12 @@ public final class Rating implements Parcelable {
Log.e(TAG, "Invalid rating style (" + starRatingStyle + ") for a star rating");
return null;
}
- if ((starRating < 0.0f) || (starRating > maxRating)) {
+ if (starRating >= 0.0f && starRating <= maxRating) {
+ return new Rating(starRatingStyle, starRating);
+ } else {
Log.e(TAG, "Trying to set out of range star-based rating");
return null;
}
- return new Rating(starRatingStyle, starRating);
}
/**
@@ -221,11 +222,11 @@ public final class Rating implements Parcelable {
* @return null if the rating is out of range, a new Rating instance otherwise.
*/
public static Rating newPercentageRating(float percent) {
- if ((percent < 0.0f) || (percent > 100.0f)) {
+ if (percent >= 0.0f && percent <= 100.0f) {
+ return new Rating(RATING_PERCENTAGE, percent);
+ } else {
Log.e(TAG, "Invalid percentage-based rating value");
return null;
- } else {
- return new Rating(RATING_PERCENTAGE, percent);
}
}
diff --git a/packages/SettingsLib/Utils/src/com/android/settingslib/utils/applications/AppUtils.java b/packages/SettingsLib/Utils/src/com/android/settingslib/utils/applications/AppUtils.java
index e7c0d9659d11..4505dad8ea12 100644
--- a/packages/SettingsLib/Utils/src/com/android/settingslib/utils/applications/AppUtils.java
+++ b/packages/SettingsLib/Utils/src/com/android/settingslib/utils/applications/AppUtils.java
@@ -52,6 +52,9 @@ public class AppUtils {
public static String getAppContentDescription(Context context, String packageName,
int userId) {
final CharSequence appLabel = getApplicationLabel(context.getPackageManager(), packageName);
+ if (appLabel == null) {
+ return "";
+ }
return context.getSystemService(UserManager.class).isManagedProfile(userId)
? context.getString(R.string.accessibility_work_profile_app_description, appLabel)
: appLabel.toString();
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index a97af4bbe324..2a699ea45abe 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -146,6 +146,7 @@
<uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS" />
<uses-permission android:name="android.permission.START_TASKS_FROM_RECENTS" />
<uses-permission android:name="android.permission.START_ACTIVITIES_FROM_BACKGROUND" />
+ <uses-permission android:name="android.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND" />
<uses-permission android:name="android.permission.ACTIVITY_EMBEDDING" />
<uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
<uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 014d73f281cc..2ea0c2294f76 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -33,6 +33,13 @@ java_library {
srcs: ["src/com/android/systemui/EventLogTags.logtags"],
}
+java_library {
+ name: "SystemUI-sensors",
+ srcs: [
+ "src/com/android/systemui/util/sensors/ThresholdSensor.java",
+ ]
+}
+
android_library {
name: "SystemUI-core",
srcs: [
diff --git a/packages/SystemUI/plugin/Android.bp b/packages/SystemUI/plugin/Android.bp
index df5561acbbc4..ab4f800d2586 100644
--- a/packages/SystemUI/plugin/Android.bp
+++ b/packages/SystemUI/plugin/Android.bp
@@ -19,7 +19,8 @@ java_library {
srcs: ["src/**/*.java"],
static_libs: [
- "PluginCoreLib"
+ "PluginCoreLib",
+ "SystemUI-sensors",
],
}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java
index 0f94bca1d815..6e86f268a725 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java
@@ -20,6 +20,7 @@ import android.net.Uri;
import android.view.MotionEvent;
import com.android.systemui.plugins.annotations.ProvidesInterface;
+import com.android.systemui.util.sensors.ThresholdSensor;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -35,12 +36,6 @@ public interface FalsingManager {
void onSuccessfulUnlock();
- void onNotificationActive();
-
- void setShowingAod(boolean showingAod);
-
- void onNotificatonStartDraggingDown();
-
boolean isUnlockingDisabled();
/** Returns true if the gesture should be rejected. */
@@ -82,66 +77,21 @@ public interface FalsingManager {
*/
boolean isFalseDoubleTap();
- void onNotificatonStopDraggingDown();
-
- void setNotificationExpanded();
-
boolean isClassifierEnabled();
- void onQsDown();
-
- void setQsExpanded(boolean expanded);
-
boolean shouldEnforceBouncer();
- void onTrackingStarted(boolean secure);
-
- void onTrackingStopped();
-
- void onLeftAffordanceOn();
-
- void onCameraOn();
-
- void onAffordanceSwipingStarted(boolean rightCorner);
-
- void onAffordanceSwipingAborted();
-
- void onStartExpandingFromPulse();
-
- void onExpansionFromPulseStopped();
-
Uri reportRejectedTouch();
- void onScreenOnFromTouch();
-
boolean isReportingEnabled();
- void onUnlockHintStarted();
-
- void onCameraHintStarted();
-
- void onLeftAffordanceHintStarted();
-
- void onScreenTurningOn();
-
- void onScreenOff();
-
- void onNotificationStopDismissing();
-
- void onNotificationDismissed();
-
- void onNotificationStartDismissing();
-
- void onNotificationDoubleTap(boolean accepted, float dx, float dy);
-
- void onBouncerShown();
-
- void onBouncerHidden();
-
void onTouchEvent(MotionEvent ev, int width, int height);
/** From com.android.systemui.Dumpable. */
void dump(FileDescriptor fd, PrintWriter pw, String[] args);
void cleanup();
+
+ /** Call to report a ProximityEvent to the FalsingManager. */
+ void onProximityEvent(ThresholdSensor.ThresholdSensorEvent proximityEvent);
}
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index ea1258f025f7..5b74687c3109 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -226,6 +226,8 @@
<string name="screenshot_saved_text">Tap to view your screenshot</string>
<!-- Notification title displayed when we fail to take a screenshot. [CHAR LIMIT=50] -->
<string name="screenshot_failed_title">Couldn\'t save screenshot</string>
+ <!-- Notification text displayed when we fail to save a screenshot due to locked storage. [CHAR LIMIT=100] -->
+ <string name="screenshot_failed_to_save_user_locked_text">Device must be unlocked before screenshot can be saved</string>
<!-- Notification text displayed when we fail to save a screenshot for unknown reasons. [CHAR LIMIT=100] -->
<string name="screenshot_failed_to_save_unknown_text">Try taking screenshot again</string>
<!-- Notification text displayed when we fail to save a screenshot. [CHAR LIMIT=100] -->
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index 182b3e114887..935f89343754 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -281,7 +281,7 @@ public class AuthContainerView extends LinearLayout
// Inflate biometric view only if necessary.
if (Utils.isBiometricAllowed(mConfig.mPromptInfo)) {
- if (config.mSensorIds.length == 1) {
+ if (config.mSensorIds.length == 1 || config.mSensorIds.length == 2) {
final int singleSensorAuthId = config.mSensorIds[0];
if (Utils.containsSensorId(mFpProps, singleSensorAuthId)) {
FingerprintSensorPropertiesInternal sensorProps = null;
@@ -313,7 +313,6 @@ public class AuthContainerView extends LinearLayout
return;
}
} else {
- // The UI currently only supports authentication with a single sensor.
Log.e(TAG, "Unsupported sensor array, length: " + config.mSensorIds.length);
mBiometricView = null;
mBackgroundView = null;
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java
new file mode 100644
index 000000000000..c05ce93f0c13
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.classifier;
+
+import android.view.MotionEvent;
+
+/**
+ * Defines a class that can be used to ingest system events for later processing.
+ */
+public interface FalsingCollector {
+ /** */
+ void onSuccessfulUnlock();
+
+ /** */
+ void onNotificationActive();
+
+ /** */
+ void setShowingAod(boolean showingAod);
+
+ /** */
+ void onNotificationStartDraggingDown();
+
+ /** */
+ void onNotificationStopDraggingDown();
+
+ /** */
+ void setNotificationExpanded();
+
+ /** */
+ void onQsDown();
+
+ /** */
+ void setQsExpanded(boolean expanded);
+
+ /** */
+ boolean shouldEnforceBouncer();
+
+ /** */
+ void onTrackingStarted(boolean secure);
+
+ /** */
+ void onTrackingStopped();
+
+ /** */
+ void onLeftAffordanceOn();
+
+ /** */
+ void onCameraOn();
+
+ /** */
+ void onAffordanceSwipingStarted(boolean rightCorner);
+
+ /** */
+ void onAffordanceSwipingAborted();
+
+ /** */
+ void onStartExpandingFromPulse();
+
+ /** */
+ void onExpansionFromPulseStopped();
+
+ /** */
+ void onScreenOnFromTouch();
+
+ /** */
+ boolean isReportingEnabled();
+
+ /** */
+ void onUnlockHintStarted();
+
+ /** */
+ void onCameraHintStarted();
+
+ /** */
+ void onLeftAffordanceHintStarted();
+
+ /** */
+ void onScreenTurningOn();
+
+ /** */
+ void onScreenOff();
+
+ /** */
+ void onNotificationStopDismissing();
+
+ /** */
+ void onNotificationDismissed();
+
+ /** */
+ void onNotificationStartDismissing();
+
+ /** */
+ void onNotificationDoubleTap(boolean accepted, float dx, float dy);
+
+ /** */
+ void onBouncerShown();
+
+ /** */
+ void onBouncerHidden();
+
+ /** */
+ void onTouchEvent(MotionEvent ev, int width, int height);
+
+ /** */
+ void cleanup();
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java
new file mode 100644
index 000000000000..a5691118261a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.classifier;
+
+import android.view.MotionEvent;
+
+/** */
+public class FalsingCollectorFake implements FalsingCollector {
+ @Override
+ public void onSuccessfulUnlock() {
+ }
+
+ @Override
+ public void onNotificationActive() {
+ }
+
+ @Override
+ public void setShowingAod(boolean showingAod) {
+ }
+
+ @Override
+ public void onNotificationStartDraggingDown() {
+ }
+
+ @Override
+ public void onNotificationStopDraggingDown() {
+ }
+
+ @Override
+ public void setNotificationExpanded() {
+ }
+
+ @Override
+ public void onQsDown() {
+ }
+
+ @Override
+ public void setQsExpanded(boolean expanded) {
+ }
+
+ @Override
+ public boolean shouldEnforceBouncer() {
+ return false;
+ }
+
+ @Override
+ public void onTrackingStarted(boolean secure) {
+ }
+
+ @Override
+ public void onTrackingStopped() {
+ }
+
+ @Override
+ public void onLeftAffordanceOn() {
+ }
+
+ @Override
+ public void onCameraOn() {
+ }
+
+ @Override
+ public void onAffordanceSwipingStarted(boolean rightCorner) {
+ }
+
+ @Override
+ public void onAffordanceSwipingAborted() {
+ }
+
+ @Override
+ public void onStartExpandingFromPulse() {
+ }
+
+ @Override
+ public void onExpansionFromPulseStopped() {
+ }
+
+ @Override
+ public void onScreenOnFromTouch() {
+ }
+
+ @Override
+ public boolean isReportingEnabled() {
+ return false;
+ }
+
+ @Override
+ public void onUnlockHintStarted() {
+ }
+
+ @Override
+ public void onCameraHintStarted() {
+ }
+
+ @Override
+ public void onLeftAffordanceHintStarted() {
+ }
+
+ @Override
+ public void onScreenTurningOn() {
+ }
+
+ @Override
+ public void onScreenOff() {
+ }
+
+ @Override
+ public void onNotificationStopDismissing() {
+ }
+
+ @Override
+ public void onNotificationDismissed() {
+ }
+
+ @Override
+ public void onNotificationStartDismissing() {
+ }
+
+ @Override
+ public void onNotificationDoubleTap(boolean accepted, float dx, float dy) {
+ }
+
+ @Override
+ public void onBouncerShown() {
+ }
+
+ @Override
+ public void onBouncerHidden() {
+ }
+
+ @Override
+ public void onTouchEvent(MotionEvent ev, int width, int height) {
+ }
+
+ @Override
+ public void cleanup() {
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
new file mode 100644
index 000000000000..3547392512a7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.classifier;
+
+import android.hardware.SensorManager;
+import android.hardware.biometrics.BiometricSourceType;
+import android.util.Log;
+import android.view.MotionEvent;
+
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.util.sensors.ProximitySensor;
+import com.android.systemui.util.sensors.ThresholdSensor;
+
+import javax.inject.Inject;
+
+@SysUISingleton
+class FalsingCollectorImpl implements FalsingCollector {
+
+ private static final boolean DEBUG = false;
+ private static final String TAG = "FalsingManager";
+ private static final String PROXIMITY_SENSOR_TAG = "FalsingManager";
+
+ private final FalsingDataProvider mFalsingDataProvider;
+ private final FalsingManager mFalsingManager;
+ private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ private final ProximitySensor mProximitySensor;
+ private final StatusBarStateController mStatusBarStateController;
+
+ private int mState;
+ private boolean mShowingAod;
+ private boolean mScreenOn;
+ private boolean mSessionStarted;
+
+ private final ThresholdSensor.Listener mSensorEventListener = this::onProximityEvent;
+
+ private final StatusBarStateController.StateListener mStatusBarStateListener =
+ new StatusBarStateController.StateListener() {
+ @Override
+ public void onStateChanged(int newState) {
+ logDebug("StatusBarState=" + StatusBarState.toShortString(newState));
+ mState = newState;
+ updateSessionActive();
+ }
+ };
+
+
+ private final KeyguardUpdateMonitorCallback mKeyguardUpdateCallback =
+ new KeyguardUpdateMonitorCallback() {
+ @Override
+ public void onBiometricAuthenticated(int userId,
+ BiometricSourceType biometricSourceType,
+ boolean isStrongBiometric) {
+ if (userId == KeyguardUpdateMonitor.getCurrentUser()
+ && biometricSourceType == BiometricSourceType.FACE) {
+ mFalsingDataProvider.setJustUnlockedWithFace(true);
+ }
+ }
+ };
+
+ @Inject
+ FalsingCollectorImpl(FalsingDataProvider falsingDataProvider, FalsingManager falsingManager,
+ KeyguardUpdateMonitor keyguardUpdateMonitor,
+ ProximitySensor proximitySensor, StatusBarStateController statusBarStateController) {
+ mFalsingDataProvider = falsingDataProvider;
+ mFalsingManager = falsingManager;
+ mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+ mProximitySensor = proximitySensor;
+ mStatusBarStateController = statusBarStateController;
+
+
+ mProximitySensor.setTag(PROXIMITY_SENSOR_TAG);
+ mProximitySensor.setDelay(SensorManager.SENSOR_DELAY_GAME);
+
+ mStatusBarStateController.addCallback(mStatusBarStateListener);
+ mState = mStatusBarStateController.getState();
+
+ mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateCallback);
+ }
+
+ @Override
+ public void onSuccessfulUnlock() {
+ mFalsingManager.onSuccessfulUnlock();
+ sessionEnd();
+ }
+
+ @Override
+ public void onNotificationActive() {
+ }
+
+ @Override
+ public void setShowingAod(boolean showingAod) {
+ mShowingAod = showingAod;
+ updateSessionActive();
+ }
+
+ @Override
+ public void onNotificationStartDraggingDown() {
+ updateInteractionType(Classifier.NOTIFICATION_DRAG_DOWN);
+ }
+
+ @Override
+ public void onNotificationStopDraggingDown() {
+ }
+
+ @Override
+ public void setNotificationExpanded() {
+ }
+
+ @Override
+ public void onQsDown() {
+ updateInteractionType(Classifier.QUICK_SETTINGS);
+ }
+
+ @Override
+ public void setQsExpanded(boolean expanded) {
+ if (expanded) {
+ unregisterSensors();
+ } else if (mSessionStarted) {
+ registerSensors();
+ }
+ }
+
+ @Override
+ public boolean shouldEnforceBouncer() {
+ return false;
+ }
+
+ @Override
+ public void onTrackingStarted(boolean secure) {
+ updateInteractionType(secure ? Classifier.BOUNCER_UNLOCK : Classifier.UNLOCK);
+ }
+
+ @Override
+ public void onTrackingStopped() {
+ }
+
+ @Override
+ public void onLeftAffordanceOn() {
+ }
+
+ @Override
+ public void onCameraOn() {
+ }
+
+ @Override
+ public void onAffordanceSwipingStarted(boolean rightCorner) {
+ updateInteractionType(
+ rightCorner ? Classifier.RIGHT_AFFORDANCE : Classifier.LEFT_AFFORDANCE);
+ }
+
+ @Override
+ public void onAffordanceSwipingAborted() {
+ }
+
+ @Override
+ public void onStartExpandingFromPulse() {
+ updateInteractionType(Classifier.PULSE_EXPAND);
+ }
+
+ @Override
+ public void onExpansionFromPulseStopped() {
+ }
+
+ @Override
+ public void onScreenOnFromTouch() {
+ onScreenTurningOn();
+ }
+
+ @Override
+ public boolean isReportingEnabled() {
+ return false;
+ }
+
+ @Override
+ public void onUnlockHintStarted() {
+ }
+
+ @Override
+ public void onCameraHintStarted() {
+ }
+
+ @Override
+ public void onLeftAffordanceHintStarted() {
+ }
+
+ @Override
+ public void onScreenTurningOn() {
+ mScreenOn = true;
+ updateSessionActive();
+ }
+
+ @Override
+ public void onScreenOff() {
+ mScreenOn = false;
+ updateSessionActive();
+ }
+
+ @Override
+ public void onNotificationStopDismissing() {
+ }
+
+ @Override
+ public void onNotificationDismissed() {
+ }
+
+ @Override
+ public void onNotificationStartDismissing() {
+ updateInteractionType(Classifier.NOTIFICATION_DISMISS);
+ }
+
+ @Override
+ public void onNotificationDoubleTap(boolean accepted, float dx, float dy) {
+ }
+
+ @Override
+ public void onBouncerShown() {
+ unregisterSensors();
+ }
+
+ @Override
+ public void onBouncerHidden() {
+ if (mSessionStarted) {
+ registerSensors();
+ }
+ }
+
+ @Override
+ public void onTouchEvent(MotionEvent ev, int width, int height) {
+ mFalsingDataProvider.onMotionEvent(ev);
+ mFalsingManager.onTouchEvent(ev, width, height);
+ }
+
+ @Override
+ public void cleanup() {
+ unregisterSensors();
+ mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateCallback);
+ mStatusBarStateController.removeCallback(mStatusBarStateListener);
+ }
+
+ private void updateInteractionType(@Classifier.InteractionType int type) {
+ logDebug("InteractionType: " + type);
+ mFalsingDataProvider.setInteractionType(type);
+ }
+
+ private boolean shouldSessionBeActive() {
+ return mScreenOn && (mState == StatusBarState.KEYGUARD) && !mShowingAod;
+ }
+
+ private void updateSessionActive() {
+ if (shouldSessionBeActive()) {
+ sessionStart();
+ } else {
+ sessionEnd();
+ }
+ }
+
+ private void sessionStart() {
+ if (!mSessionStarted && shouldSessionBeActive()) {
+ logDebug("Starting Session");
+ mSessionStarted = true;
+ mFalsingDataProvider.setJustUnlockedWithFace(false);
+ registerSensors();
+ mFalsingDataProvider.onSessionStarted();
+ }
+ }
+
+ private void sessionEnd() {
+ if (mSessionStarted) {
+ logDebug("Ending Session");
+ mSessionStarted = false;
+ unregisterSensors();
+ mFalsingDataProvider.onSessionEnd();
+ }
+ }
+
+ private void registerSensors() {
+ if (!mFalsingDataProvider.isWirelessCharging()) {
+ mProximitySensor.register(mSensorEventListener);
+ }
+ }
+
+ private void unregisterSensors() {
+ mProximitySensor.unregister(mSensorEventListener);
+ }
+
+ private void onProximityEvent(ThresholdSensor.ThresholdSensorEvent proximityEvent) {
+ // TODO: some of these classifiers might allow us to abort early, meaning we don't have to
+ // make these calls.
+ mFalsingManager.onProximityEvent(proximityEvent);
+ }
+
+
+ static void logDebug(String msg) {
+ logDebug(msg, null);
+ }
+
+ static void logDebug(String msg, Throwable throwable) {
+ if (DEBUG) {
+ Log.d(TAG, msg, throwable);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingDataProvider.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
index 4681f9709a7d..b29871c1c3d0 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingDataProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,14 +14,17 @@
* limitations under the License.
*/
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.MotionEvent.PointerCoords;
import android.view.MotionEvent.PointerProperties;
-import com.android.systemui.classifier.Classifier;
+import com.android.systemui.classifier.brightline.BrightLineFalsingManager;
+import com.android.systemui.classifier.brightline.FalsingClassifier;
+import com.android.systemui.classifier.brightline.TimeLimitedMotionEventBuffer;
+import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.util.time.SystemClock;
@@ -36,6 +39,7 @@ import javax.inject.Inject;
/**
* Acts as a cache and utility class for FalsingClassifiers.
*/
+@SysUISingleton
public class FalsingDataProvider {
private static final long MOTION_EVENT_AGE_MS = 1000;
@@ -48,6 +52,7 @@ public class FalsingDataProvider {
private final SystemClock mSystemClock;
private final float mXdpi;
private final float mYdpi;
+ private final List<SessionListener> mSessionListeners = new ArrayList<>();
private @Classifier.InteractionType int mInteractionType;
private final Deque<TimeLimitedMotionEventBuffer> mExtendedMotionEvents = new LinkedList<>();
@@ -57,9 +62,9 @@ public class FalsingDataProvider {
private boolean mDirty = true;
private float mAngle = 0;
- private MotionEvent mFirstActualMotionEvent;
private MotionEvent mFirstRecentMotionEvent;
private MotionEvent mLastMotionEvent;
+ private boolean mJustUnlockedWithFace;
@Inject
public FalsingDataProvider(DisplayMetrics displayMetrics, BatteryController batteryController,
@@ -76,10 +81,6 @@ public class FalsingDataProvider {
}
void onMotionEvent(MotionEvent motionEvent) {
- if (motionEvent.getActionMasked() == MotionEvent.ACTION_DOWN) {
- mFirstActualMotionEvent = motionEvent;
- }
-
List<MotionEvent> motionEvents = unpackMotionEvent(motionEvent);
FalsingClassifier.logDebug("Unpacked into: " + motionEvents.size());
if (BrightLineFalsingManager.DEBUG) {
@@ -103,29 +104,29 @@ public class FalsingDataProvider {
}
/** Returns screen width in pixels. */
- int getWidthPixels() {
+ public int getWidthPixels() {
return mWidthPixels;
}
/** Returns screen height in pixels. */
- int getHeightPixels() {
+ public int getHeightPixels() {
return mHeightPixels;
}
- float getXdpi() {
+ public float getXdpi() {
return mXdpi;
}
- float getYdpi() {
+ public float getYdpi() {
return mYdpi;
}
- List<MotionEvent> getRecentMotionEvents() {
+ public List<MotionEvent> getRecentMotionEvents() {
return mRecentMotionEvents;
}
/** Returns recent gestures, exclusive of the most recent gesture. Newer gestures come first. */
- Queue<? extends List<MotionEvent>> getHistoricalMotionEvents() {
+ public Queue<? extends List<MotionEvent>> getHistoricalMotionEvents() {
long nowMs = mSystemClock.uptimeMillis();
mExtendedMotionEvents.removeIf(
@@ -137,31 +138,38 @@ public class FalsingDataProvider {
/**
* interactionType is defined by {@link com.android.systemui.classifier.Classifier}.
*/
- final void setInteractionType(@Classifier.InteractionType int interactionType) {
+ public final void setInteractionType(@Classifier.InteractionType int interactionType) {
if (mInteractionType != interactionType) {
mInteractionType = interactionType;
mDirty = true;
}
}
+ /**
+ * Returns true if new data has been supplied since the last time this class has been accessed.
+ */
public boolean isDirty() {
return mDirty;
}
- final int getInteractionType() {
+ /** Return the interaction type that is being compared against for falsing. */
+ public final int getInteractionType() {
return mInteractionType;
}
- MotionEvent getFirstActualMotionEvent() {
- return mFirstActualMotionEvent;
- }
-
- MotionEvent getFirstRecentMotionEvent() {
+ /**
+ * Get the first recorded {@link MotionEvent} of the most recent gesture.
+ *
+ * Note that MotionEvents are not kept forever. As a gesture gets longer in duration, older
+ * MotionEvents may expire and be ejected.
+ */
+ public MotionEvent getFirstRecentMotionEvent() {
recalculateData();
return mFirstRecentMotionEvent;
}
- MotionEvent getLastMotionEvent() {
+ /** Get the last recorded {@link MotionEvent}. */
+ public MotionEvent getLastMotionEvent() {
recalculateData();
return mLastMotionEvent;
}
@@ -171,12 +179,13 @@ public class FalsingDataProvider {
*
* The angle will be in radians, always be between 0 and 2*PI, inclusive.
*/
- float getAngle() {
+ public float getAngle() {
recalculateData();
return mAngle;
}
- boolean isHorizontal() {
+ /** Returns if the most recent gesture is more horizontal than vertical. */
+ public boolean isHorizontal() {
recalculateData();
if (mRecentMotionEvents.isEmpty()) {
return false;
@@ -186,7 +195,13 @@ public class FalsingDataProvider {
.abs(mFirstRecentMotionEvent.getY() - mLastMotionEvent.getY());
}
- boolean isRight() {
+ /**
+ * Is the most recent gesture more right than left.
+ *
+ * This does not mean the gesture is mostly horizontal. Simply that it ended at least one pixel
+ * to the right of where it started. See also {@link #isHorizontal()}.
+ */
+ public boolean isRight() {
recalculateData();
if (mRecentMotionEvents.isEmpty()) {
return false;
@@ -195,11 +210,18 @@ public class FalsingDataProvider {
return mLastMotionEvent.getX() > mFirstRecentMotionEvent.getX();
}
- boolean isVertical() {
+ /** Returns if the most recent gesture is more vertical than horizontal. */
+ public boolean isVertical() {
return !isHorizontal();
}
- boolean isUp() {
+ /**
+ * Is the most recent gesture more up than down.
+ *
+ * This does not mean the gesture is mostly vertical. Simply that it ended at least one pixel
+ * higher than it started. See also {@link #isVertical()}.
+ */
+ public boolean isUp() {
recalculateData();
if (mRecentMotionEvents.isEmpty()) {
return false;
@@ -209,7 +231,7 @@ public class FalsingDataProvider {
}
/** Returns true if phone is being charged without a cable. */
- boolean isWirelessCharging() {
+ public boolean isWirelessCharging() {
return mBatteryController.isWirelessCharging();
}
@@ -292,9 +314,21 @@ public class FalsingDataProvider {
return motionEvents;
}
- void onSessionEnd() {
- mFirstActualMotionEvent = null;
+ /** Register a {@link SessionListener}. */
+ public void addSessionListener(SessionListener listener) {
+ mSessionListeners.add(listener);
+ }
+
+ /** Unregister a {@link SessionListener}. */
+ public void removeSessionListener(SessionListener listener) {
+ mSessionListeners.remove(listener);
+ }
+ void onSessionStarted() {
+ mSessionListeners.forEach(SessionListener::onSessionStarted);
+ }
+
+ void onSessionEnd() {
for (MotionEvent ev : mRecentMotionEvents) {
ev.recycle();
}
@@ -302,5 +336,24 @@ public class FalsingDataProvider {
mRecentMotionEvents.clear();
mDirty = true;
+
+ mSessionListeners.forEach(SessionListener::onSessionEnded);
+ }
+
+ public boolean isJustUnlockedWithFace() {
+ return mJustUnlockedWithFace;
+ }
+
+ public void setJustUnlockedWithFace(boolean justUnlockedWithFace) {
+ mJustUnlockedWithFace = justUnlockedWithFace;
+ }
+
+ /** Implement to be alerted abotu the beginning and ending of falsing tracking. */
+ public interface SessionListener {
+ /** Called when the lock screen is shown and falsing-tracking begins. */
+ void onSessionStarted();
+
+ /** Called when the lock screen exits and falsing-tracking ends. */
+ void onSessionEnded();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java
index 121484303b99..32d27bcc01a6 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java
@@ -21,6 +21,7 @@ import android.view.MotionEvent;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.util.sensors.ThresholdSensor;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -43,21 +44,6 @@ public class FalsingManagerFake implements FalsingManager {
}
- @Override
- public void onNotificationActive() {
-
- }
-
- @Override
- public void setShowingAod(boolean showingAod) {
-
- }
-
- @Override
- public void onNotificatonStartDraggingDown() {
-
- }
-
@VisibleForTesting
public void setIsUnlockingDisabled(boolean isUnlockingDisabled) {
mIsUnlockingDisabled = isUnlockingDisabled;
@@ -100,16 +86,6 @@ public class FalsingManagerFake implements FalsingManager {
return mIsFalseDoubleTap;
}
- @Override
- public void onNotificatonStopDraggingDown() {
-
- }
-
- @Override
- public void setNotificationExpanded() {
-
- }
-
@VisibleForTesting
public void setIsClassiferEnabled(boolean isClassiferEnabled) {
mIsClassiferEnabled = isClassiferEnabled;
@@ -121,76 +97,15 @@ public class FalsingManagerFake implements FalsingManager {
}
@Override
- public void onQsDown() {
-
- }
-
- @Override
- public void setQsExpanded(boolean expanded) {
-
- }
-
- @VisibleForTesting
- public void setShouldEnforceBouncer(boolean shouldEnforceBouncer) {
- mShouldEnforceBouncer = shouldEnforceBouncer;
- }
-
- @Override
public boolean shouldEnforceBouncer() {
return mShouldEnforceBouncer;
}
@Override
- public void onTrackingStarted(boolean secure) {
-
- }
-
- @Override
- public void onTrackingStopped() {
-
- }
-
- @Override
- public void onLeftAffordanceOn() {
-
- }
-
- @Override
- public void onCameraOn() {
-
- }
-
- @Override
- public void onAffordanceSwipingStarted(boolean rightCorner) {
-
- }
-
- @Override
- public void onAffordanceSwipingAborted() {
-
- }
-
- @Override
- public void onStartExpandingFromPulse() {
-
- }
-
- @Override
- public void onExpansionFromPulseStopped() {
-
- }
-
- @Override
public Uri reportRejectedTouch() {
return null;
}
- @Override
- public void onScreenOnFromTouch() {
-
- }
-
-
@VisibleForTesting
public void setIsReportingEnabled(boolean isReportingEnabled) {
mIsReportingEnabled = isReportingEnabled;
@@ -202,70 +117,20 @@ public class FalsingManagerFake implements FalsingManager {
}
@Override
- public void onUnlockHintStarted() {
-
- }
-
- @Override
- public void onCameraHintStarted() {
-
- }
-
- @Override
- public void onLeftAffordanceHintStarted() {
-
- }
-
- @Override
- public void onScreenTurningOn() {
-
- }
-
- @Override
- public void onScreenOff() {
-
- }
-
- @Override
- public void onNotificationStopDismissing() {
-
- }
-
- @Override
- public void onNotificationDismissed() {
-
- }
-
- @Override
- public void onNotificationStartDismissing() {
-
- }
-
- @Override
- public void onNotificationDoubleTap(boolean accepted, float dx, float dy) {
-
- }
-
- @Override
- public void onBouncerShown() {
+ public void onTouchEvent(MotionEvent ev, int width, int height) {
}
@Override
- public void onBouncerHidden() {
-
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
}
@Override
- public void onTouchEvent(MotionEvent ev, int width, int height) {
-
+ public void cleanup() {
}
@Override
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- }
+ public void onProximityEvent(ThresholdSensor.ThresholdSensorEvent proximityEvent) {
- @Override
- public void cleanup() {
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
index 814fff9c6d43..74629411c13d 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
@@ -17,37 +17,30 @@
package com.android.systemui.classifier;
import android.content.Context;
-import android.content.res.Resources;
-import android.hardware.SensorManager;
import android.net.Uri;
import android.provider.DeviceConfig;
import android.view.MotionEvent;
-import android.view.ViewConfiguration;
import androidx.annotation.NonNull;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.Dumpable;
import com.android.systemui.classifier.brightline.BrightLineFalsingManager;
-import com.android.systemui.classifier.brightline.FalsingDataProvider;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.dock.DockManager;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.FalsingPlugin;
import com.android.systemui.plugins.PluginListener;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.util.DeviceConfigProxy;
-import com.android.systemui.util.sensors.ProximitySensor;
+import com.android.systemui.util.sensors.ThresholdSensor;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.concurrent.Executor;
import javax.inject.Inject;
+import javax.inject.Provider;
/**
* Simple passthrough implementation of {@link FalsingManager} allowing plugins to swap in.
@@ -57,21 +50,14 @@ import javax.inject.Inject;
@SysUISingleton
public class FalsingManagerProxy implements FalsingManager, Dumpable {
- private static final String PROXIMITY_SENSOR_TAG = "FalsingManager";
private static final String DUMPABLE_TAG = "FalsingManager";
public static final String FALSING_REMAIN_LOCKED = "falsing_failure_after_attempts";
public static final String FALSING_SUCCESS = "falsing_success_after_attempts";
private final PluginManager mPluginManager;
- private final ProximitySensor mProximitySensor;
- private final Resources mResources;
- private final ViewConfiguration mViewConfiguration;
- private final FalsingDataProvider mFalsingDataProvider;
private final DeviceConfigProxy mDeviceConfig;
- private final DockManager mDockManager;
- private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ private final Provider<BrightLineFalsingManager> mBrightLineFalsingManagerProvider;
private final DumpManager mDumpManager;
- private final StatusBarStateController mStatusBarStateController;
final PluginListener<FalsingPlugin> mPluginListener;
private FalsingManager mInternalFalsingManager;
@@ -81,31 +67,15 @@ public class FalsingManagerProxy implements FalsingManager, Dumpable {
@Inject
FalsingManagerProxy(PluginManager pluginManager, @Main Executor executor,
- ProximitySensor proximitySensor,
- DeviceConfigProxy deviceConfig, DockManager dockManager,
- KeyguardUpdateMonitor keyguardUpdateMonitor,
- DumpManager dumpManager,
- StatusBarStateController statusBarStateController,
- @Main Resources resources,
- ViewConfiguration viewConfiguration,
- FalsingDataProvider falsingDataProvider) {
+ DeviceConfigProxy deviceConfig, DumpManager dumpManager,
+ Provider<BrightLineFalsingManager> brightLineFalsingManagerProvider) {
mPluginManager = pluginManager;
- mProximitySensor = proximitySensor;
- mDockManager = dockManager;
- mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mDumpManager = dumpManager;
- mStatusBarStateController = statusBarStateController;
- mResources = resources;
- mViewConfiguration = viewConfiguration;
- mFalsingDataProvider = falsingDataProvider;
- mProximitySensor.setTag(PROXIMITY_SENSOR_TAG);
- mProximitySensor.setDelay(SensorManager.SENSOR_DELAY_GAME);
mDeviceConfig = deviceConfig;
+ mBrightLineFalsingManagerProvider = brightLineFalsingManagerProvider;
setupFalsingManager();
mDeviceConfig.addOnPropertiesChangedListener(
- DeviceConfig.NAMESPACE_SYSTEMUI,
- executor,
- mDeviceConfigListener
+ DeviceConfig.NAMESPACE_SYSTEMUI, executor, mDeviceConfigListener
);
mPluginListener = new PluginListener<FalsingPlugin>() {
@@ -144,24 +114,7 @@ public class FalsingManagerProxy implements FalsingManager, Dumpable {
if (mInternalFalsingManager != null) {
mInternalFalsingManager.cleanup();
}
- mInternalFalsingManager = new BrightLineFalsingManager(
- mFalsingDataProvider,
- mKeyguardUpdateMonitor,
- mProximitySensor,
- mDeviceConfig,
- mResources,
- mViewConfiguration,
- mDockManager,
- mStatusBarStateController
- );
- }
-
- /**
- * Returns the FalsingManager implementation in use.
- */
- @VisibleForTesting
- FalsingManager getInternalFalsingManager() {
- return mInternalFalsingManager;
+ mInternalFalsingManager = mBrightLineFalsingManagerProvider.get();
}
@Override
@@ -170,21 +123,6 @@ public class FalsingManagerProxy implements FalsingManager, Dumpable {
}
@Override
- public void onNotificationActive() {
- mInternalFalsingManager.onNotificationActive();
- }
-
- @Override
- public void setShowingAod(boolean showingAod) {
- mInternalFalsingManager.setShowingAod(showingAod);
- }
-
- @Override
- public void onNotificatonStartDraggingDown() {
- mInternalFalsingManager.onNotificatonStartDraggingDown();
- }
-
- @Override
public boolean isUnlockingDisabled() {
return mInternalFalsingManager.isUnlockingDisabled();
}
@@ -194,7 +132,6 @@ public class FalsingManagerProxy implements FalsingManager, Dumpable {
return mInternalFalsingManager.isFalseTouch(interactionType);
}
-
@Override
public boolean isFalseTap(boolean robustCheck) {
return mInternalFalsingManager.isFalseTap(robustCheck);
@@ -206,148 +143,33 @@ public class FalsingManagerProxy implements FalsingManager, Dumpable {
}
@Override
- public void onNotificatonStopDraggingDown() {
- mInternalFalsingManager.onNotificatonStartDraggingDown();
- }
-
- @Override
- public void setNotificationExpanded() {
- mInternalFalsingManager.setNotificationExpanded();
- }
-
- @Override
public boolean isClassifierEnabled() {
return mInternalFalsingManager.isClassifierEnabled();
}
@Override
- public void onQsDown() {
- mInternalFalsingManager.onQsDown();
- }
-
- @Override
- public void setQsExpanded(boolean expanded) {
- mInternalFalsingManager.setQsExpanded(expanded);
- }
-
- @Override
public boolean shouldEnforceBouncer() {
return mInternalFalsingManager.shouldEnforceBouncer();
}
@Override
- public void onTrackingStarted(boolean secure) {
- mInternalFalsingManager.onTrackingStarted(secure);
- }
-
- @Override
- public void onTrackingStopped() {
- mInternalFalsingManager.onTrackingStopped();
- }
-
- @Override
- public void onLeftAffordanceOn() {
- mInternalFalsingManager.onLeftAffordanceOn();
- }
-
- @Override
- public void onCameraOn() {
- mInternalFalsingManager.onCameraOn();
- }
-
- @Override
- public void onAffordanceSwipingStarted(boolean rightCorner) {
- mInternalFalsingManager.onAffordanceSwipingStarted(rightCorner);
- }
-
- @Override
- public void onAffordanceSwipingAborted() {
- mInternalFalsingManager.onAffordanceSwipingAborted();
- }
-
- @Override
- public void onStartExpandingFromPulse() {
- mInternalFalsingManager.onStartExpandingFromPulse();
- }
-
- @Override
- public void onExpansionFromPulseStopped() {
- mInternalFalsingManager.onExpansionFromPulseStopped();
- }
-
- @Override
public Uri reportRejectedTouch() {
return mInternalFalsingManager.reportRejectedTouch();
}
@Override
- public void onScreenOnFromTouch() {
- mInternalFalsingManager.onScreenOnFromTouch();
- }
-
- @Override
public boolean isReportingEnabled() {
return mInternalFalsingManager.isReportingEnabled();
}
@Override
- public void onUnlockHintStarted() {
- mInternalFalsingManager.onUnlockHintStarted();
- }
-
- @Override
- public void onCameraHintStarted() {
- mInternalFalsingManager.onCameraHintStarted();
- }
-
- @Override
- public void onLeftAffordanceHintStarted() {
- mInternalFalsingManager.onLeftAffordanceHintStarted();
- }
-
- @Override
- public void onScreenTurningOn() {
- mInternalFalsingManager.onScreenTurningOn();
- }
-
- @Override
- public void onScreenOff() {
- mInternalFalsingManager.onScreenOff();
- }
-
- @Override
- public void onNotificationStopDismissing() {
- mInternalFalsingManager.onNotificationStopDismissing();
- }
-
- @Override
- public void onNotificationDismissed() {
- mInternalFalsingManager.onNotificationDismissed();
- }
-
- @Override
- public void onNotificationStartDismissing() {
- mInternalFalsingManager.onNotificationStartDismissing();
- }
-
- @Override
- public void onNotificationDoubleTap(boolean accepted, float dx, float dy) {
- mInternalFalsingManager.onNotificationDoubleTap(accepted, dx, dy);
- }
-
- @Override
- public void onBouncerShown() {
- mInternalFalsingManager.onBouncerShown();
- }
-
- @Override
- public void onBouncerHidden() {
- mInternalFalsingManager.onBouncerHidden();
+ public void onTouchEvent(MotionEvent ev, int width, int height) {
+ mInternalFalsingManager.onTouchEvent(ev, width, height);
}
@Override
- public void onTouchEvent(MotionEvent ev, int width, int height) {
- mInternalFalsingManager.onTouchEvent(ev, width, height);
+ public void onProximityEvent(ThresholdSensor.ThresholdSensorEvent proximityEvent) {
+ mInternalFalsingManager.onProximityEvent(proximityEvent);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java
new file mode 100644
index 000000000000..937bcbaa6222
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.classifier;
+
+import com.android.systemui.dagger.SysUISingleton;
+
+import dagger.Binds;
+import dagger.Module;
+
+/** Dagger Module for Falsing. */
+@Module
+public interface FalsingModule {
+ /** */
+ @Binds
+ @SysUISingleton
+ FalsingCollector bindsFalsingCollector(FalsingCollectorImpl impl);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
index 334102d68507..f6b8b4c92049 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
@@ -16,12 +16,10 @@
package com.android.systemui.classifier.brightline;
-import static com.android.systemui.classifier.FalsingManagerProxy.FALSING_REMAIN_LOCKED;
import static com.android.systemui.classifier.FalsingManagerProxy.FALSING_SUCCESS;
import android.app.ActivityManager;
import android.content.res.Resources;
-import android.hardware.biometrics.BiometricSourceType;
import android.net.Uri;
import android.os.Build;
import android.util.IndentingPrintWriter;
@@ -32,18 +30,15 @@ import android.view.ViewConfiguration;
import androidx.annotation.NonNull;
import com.android.internal.logging.MetricsLogger;
-import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.R;
import com.android.systemui.classifier.Classifier;
+import com.android.systemui.classifier.FalsingDataProvider;
+import com.android.systemui.classifier.FalsingDataProvider.SessionListener;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dock.DockManager;
import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.NotificationTapHelper;
import com.android.systemui.util.DeviceConfigProxy;
-import com.android.systemui.util.sensors.ProximitySensor;
import com.android.systemui.util.sensors.ThresholdSensor;
import java.io.FileDescriptor;
@@ -56,30 +51,25 @@ import java.util.Queue;
import java.util.StringJoiner;
import java.util.stream.Collectors;
+import javax.inject.Inject;
+
/**
* FalsingManager designed to make clear why a touch was rejected.
*/
public class BrightLineFalsingManager implements FalsingManager {
private static final String TAG = "FalsingManager";
- static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ public static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final int RECENT_INFO_LOG_SIZE = 40;
private static final int RECENT_SWIPE_LOG_SIZE = 20;
private final FalsingDataProvider mDataProvider;
- private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- private final ProximitySensor mProximitySensor;
private final DockManager mDockManager;
- private final StatusBarStateController mStatusBarStateController;
private final SingleTapClassifier mSingleTapClassifier;
private final DoubleTapClassifier mDoubleTapClassifier;
- private boolean mSessionStarted;
- private MetricsLogger mMetricsLogger;
+ private final MetricsLogger mMetricsLogger;
private int mIsFalseTouchCalls;
- private boolean mShowingAod;
- private boolean mScreenOn;
- private boolean mJustUnlockedWithFace;
private static final Queue<String> RECENT_INFO_LOG =
new ArrayDeque<>(RECENT_INFO_LOG_SIZE + 1);
private static final Queue<DebugSwipeRecord> RECENT_SWIPES =
@@ -87,46 +77,26 @@ public class BrightLineFalsingManager implements FalsingManager {
private final List<FalsingClassifier> mClassifiers;
- private ThresholdSensor.Listener mSensorEventListener = this::onProximityEvent;
-
- private final KeyguardUpdateMonitorCallback mKeyguardUpdateCallback =
- new KeyguardUpdateMonitorCallback() {
- @Override
- public void onBiometricAuthenticated(int userId,
- BiometricSourceType biometricSourceType,
- boolean isStrongBiometric) {
- if (userId == KeyguardUpdateMonitor.getCurrentUser()
- && biometricSourceType == BiometricSourceType.FACE) {
- mJustUnlockedWithFace = true;
- }
- }
- };
- private boolean mPreviousResult = false;
+ private final SessionListener mSessionListener = new SessionListener() {
+ @Override
+ public void onSessionEnded() {
+ mClassifiers.forEach(FalsingClassifier::onSessionEnded);
+ }
- private StatusBarStateController.StateListener mStatusBarStateListener =
- new StatusBarStateController.StateListener() {
@Override
- public void onStateChanged(int newState) {
- logDebug("StatusBarState=" + StatusBarState.toShortString(newState));
- mState = newState;
- updateSessionActive();
+ public void onSessionStarted() {
+ mClassifiers.forEach(FalsingClassifier::onSessionStarted);
}
};
- private int mState;
+ private boolean mPreviousResult = false;
+
+ @Inject
public BrightLineFalsingManager(FalsingDataProvider falsingDataProvider,
- KeyguardUpdateMonitor keyguardUpdateMonitor, ProximitySensor proximitySensor,
DeviceConfigProxy deviceConfigProxy, @Main Resources resources,
- ViewConfiguration viewConfiguration, DockManager dockManager,
- StatusBarStateController statusBarStateController) {
- mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+ ViewConfiguration viewConfiguration, DockManager dockManager) {
mDataProvider = falsingDataProvider;
- mProximitySensor = proximitySensor;
mDockManager = dockManager;
- mStatusBarStateController = statusBarStateController;
- mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateCallback);
- mStatusBarStateController.addCallback(mStatusBarStateListener);
- mState = mStatusBarStateController.getState();
mMetricsLogger = new MetricsLogger();
mClassifiers = new ArrayList<>();
@@ -146,58 +116,8 @@ public class BrightLineFalsingManager implements FalsingManager {
mDoubleTapClassifier = new DoubleTapClassifier(mDataProvider, mSingleTapClassifier,
resources.getDimension(R.dimen.double_tap_slop),
NotificationTapHelper.DOUBLE_TAP_TIMEOUT_MS);
- }
-
- private void registerSensors() {
- if (!mDataProvider.isWirelessCharging()) {
- mProximitySensor.register(mSensorEventListener);
- }
- }
-
- private void unregisterSensors() {
- mProximitySensor.unregister(mSensorEventListener);
- }
- private void sessionStart() {
- if (!mSessionStarted && shouldSessionBeActive()) {
- logDebug("Starting Session");
- mSessionStarted = true;
- mJustUnlockedWithFace = false;
- registerSensors();
- mClassifiers.forEach(FalsingClassifier::onSessionStarted);
- }
- }
-
- private void sessionEnd() {
- if (mSessionStarted) {
- logDebug("Ending Session");
- mSessionStarted = false;
- unregisterSensors();
- mDataProvider.onSessionEnd();
- mClassifiers.forEach(FalsingClassifier::onSessionEnded);
- if (mIsFalseTouchCalls != 0) {
- mMetricsLogger.histogram(FALSING_REMAIN_LOCKED, mIsFalseTouchCalls);
- mIsFalseTouchCalls = 0;
- }
- }
- }
-
-
- private void updateSessionActive() {
- if (shouldSessionBeActive()) {
- sessionStart();
- } else {
- sessionEnd();
- }
- }
-
- private boolean shouldSessionBeActive() {
- return mScreenOn && (mState == StatusBarState.KEYGUARD) && !mShowingAod;
- }
-
- private void updateInteractionType(@Classifier.InteractionType int type) {
- logDebug("InteractionType: " + type);
- mDataProvider.setInteractionType(type);
+ mDataProvider.addSessionListener(mSessionListener);
}
@Override
@@ -212,8 +132,9 @@ public class BrightLineFalsingManager implements FalsingManager {
return mPreviousResult;
}
- mPreviousResult = !ActivityManager.isRunningInUserTestHarness() && !mJustUnlockedWithFace
- && !mDockManager.isDocked() && mClassifiers.stream().anyMatch(falsingClassifier -> {
+ mPreviousResult = !ActivityManager.isRunningInUserTestHarness()
+ && !mDataProvider.isJustUnlockedWithFace() && !mDockManager.isDocked()
+ && mClassifiers.stream().anyMatch(falsingClassifier -> {
boolean result = falsingClassifier.isFalseTouch();
if (result) {
logInfo(String.format(
@@ -245,9 +166,8 @@ public class BrightLineFalsingManager implements FalsingManager {
(int) (motionEvent.getEventTime() - motionEvent.getDownTime())))
.collect(Collectors.toList())));
while (RECENT_SWIPES.size() > RECENT_INFO_LOG_SIZE) {
- DebugSwipeRecord record = RECENT_SWIPES.remove();
+ RECENT_SWIPES.remove();
}
-
}
return mPreviousResult;
@@ -287,11 +207,11 @@ public class BrightLineFalsingManager implements FalsingManager {
public void onTouchEvent(MotionEvent motionEvent, int width, int height) {
// TODO: some of these classifiers might allow us to abort early, meaning we don't have to
// make these calls.
- mDataProvider.onMotionEvent(motionEvent);
mClassifiers.forEach((classifier) -> classifier.onTouchEvent(motionEvent));
}
- private void onProximityEvent(ThresholdSensor.ThresholdSensorEvent proximityEvent) {
+ @Override
+ public void onProximityEvent(ThresholdSensor.ThresholdSensorEvent proximityEvent) {
// TODO: some of these classifiers might allow us to abort early, meaning we don't have to
// make these calls.
mClassifiers.forEach((classifier) -> classifier.onProximityEvent(proximityEvent));
@@ -303,22 +223,6 @@ public class BrightLineFalsingManager implements FalsingManager {
mMetricsLogger.histogram(FALSING_SUCCESS, mIsFalseTouchCalls);
mIsFalseTouchCalls = 0;
}
- sessionEnd();
- }
-
- @Override
- public void onNotificationActive() {
- }
-
- @Override
- public void setShowingAod(boolean showingAod) {
- mShowingAod = showingAod;
- updateSessionActive();
- }
-
- @Override
- public void onNotificatonStartDraggingDown() {
- updateInteractionType(Classifier.NOTIFICATION_DRAG_DOWN);
}
@Override
@@ -326,147 +230,29 @@ public class BrightLineFalsingManager implements FalsingManager {
return false;
}
-
- @Override
- public void onNotificatonStopDraggingDown() {
- }
-
- @Override
- public void setNotificationExpanded() {
- }
-
- @Override
- public void onQsDown() {
- updateInteractionType(Classifier.QUICK_SETTINGS);
- }
-
- @Override
- public void setQsExpanded(boolean expanded) {
- if (expanded) {
- unregisterSensors();
- } else if (mSessionStarted) {
- registerSensors();
- }
- }
-
@Override
public boolean shouldEnforceBouncer() {
return false;
}
@Override
- public void onTrackingStarted(boolean secure) {
- updateInteractionType(secure ? Classifier.BOUNCER_UNLOCK : Classifier.UNLOCK);
- }
-
- @Override
- public void onTrackingStopped() {
- }
-
- @Override
- public void onLeftAffordanceOn() {
- }
-
- @Override
- public void onCameraOn() {
- }
-
- @Override
- public void onAffordanceSwipingStarted(boolean rightCorner) {
- updateInteractionType(
- rightCorner ? Classifier.RIGHT_AFFORDANCE : Classifier.LEFT_AFFORDANCE);
- }
-
- @Override
- public void onAffordanceSwipingAborted() {
- }
-
- @Override
- public void onStartExpandingFromPulse() {
- updateInteractionType(Classifier.PULSE_EXPAND);
- }
-
- @Override
- public void onExpansionFromPulseStopped() {
- }
-
- @Override
public Uri reportRejectedTouch() {
return null;
}
@Override
- public void onScreenOnFromTouch() {
- onScreenTurningOn();
- }
-
- @Override
public boolean isReportingEnabled() {
return false;
}
@Override
- public void onUnlockHintStarted() {
- }
-
- @Override
- public void onCameraHintStarted() {
- }
-
- @Override
- public void onLeftAffordanceHintStarted() {
- }
-
- @Override
- public void onScreenTurningOn() {
- mScreenOn = true;
- updateSessionActive();
- }
-
- @Override
- public void onScreenOff() {
- mScreenOn = false;
- updateSessionActive();
- }
-
-
- @Override
- public void onNotificationStopDismissing() {
- }
-
- @Override
- public void onNotificationDismissed() {
- }
-
- @Override
- public void onNotificationStartDismissing() {
- updateInteractionType(Classifier.NOTIFICATION_DISMISS);
- }
-
- @Override
- public void onNotificationDoubleTap(boolean b, float v, float v1) {
- }
-
- @Override
- public void onBouncerShown() {
- unregisterSensors();
- }
-
- @Override
- public void onBouncerHidden() {
- if (mSessionStarted) {
- registerSensors();
- }
- }
-
- @Override
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
ipw.println("BRIGHTLINE FALSING MANAGER");
ipw.print("classifierEnabled=");
ipw.println(isClassifierEnabled() ? 1 : 0);
ipw.print("mJustUnlockedWithFace=");
- ipw.println(mJustUnlockedWithFace ? 1 : 0);
+ ipw.println(mDataProvider.isJustUnlockedWithFace() ? 1 : 0);
ipw.print("isDocked=");
ipw.println(mDockManager.isDocked() ? 1 : 0);
ipw.print("width=");
@@ -496,9 +282,7 @@ public class BrightLineFalsingManager implements FalsingManager {
@Override
public void cleanup() {
- unregisterSensors();
- mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateCallback);
- mStatusBarStateController.removeCallback(mStatusBarStateListener);
+ mDataProvider.removeSessionListener(mSessionListener);
}
static void logDebug(String msg) {
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DiagonalClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/DiagonalClassifier.java
index 520e0a12dec4..a73ccf575249 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DiagonalClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/DiagonalClassifier.java
@@ -23,6 +23,7 @@ import static com.android.systemui.classifier.Classifier.RIGHT_AFFORDANCE;
import android.provider.DeviceConfig;
+import com.android.systemui.classifier.FalsingDataProvider;
import com.android.systemui.util.DeviceConfigProxy;
import java.util.Locale;
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DistanceClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/DistanceClassifier.java
index 0329183e6048..893d43579ba5 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DistanceClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/DistanceClassifier.java
@@ -27,6 +27,7 @@ import android.provider.DeviceConfig;
import android.view.MotionEvent;
import android.view.VelocityTracker;
+import com.android.systemui.classifier.FalsingDataProvider;
import com.android.systemui.util.DeviceConfigProxy;
import java.util.List;
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DoubleTapClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/DoubleTapClassifier.java
index d3af1c347048..a27ea6172414 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DoubleTapClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/DoubleTapClassifier.java
@@ -18,6 +18,8 @@ package com.android.systemui.classifier.brightline;
import android.view.MotionEvent;
+import com.android.systemui.classifier.FalsingDataProvider;
+
import java.util.List;
import java.util.Queue;
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingClassifier.java
index ed417b3d09ec..568dc432729f 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingClassifier.java
@@ -19,6 +19,7 @@ package com.android.systemui.classifier.brightline;
import android.view.MotionEvent;
import com.android.systemui.classifier.Classifier;
+import com.android.systemui.classifier.FalsingDataProvider;
import com.android.systemui.util.sensors.ProximitySensor;
import java.util.List;
@@ -27,7 +28,7 @@ import java.util.Queue;
/**
* Base class for rules that determine False touches.
*/
-abstract class FalsingClassifier {
+public abstract class FalsingClassifier {
private final FalsingDataProvider mDataProvider;
FalsingClassifier(FalsingDataProvider dataProvider) {
@@ -126,15 +127,18 @@ abstract class FalsingClassifier {
*/
abstract String getReason();
- static void logDebug(String msg) {
+ /** */
+ public static void logDebug(String msg) {
BrightLineFalsingManager.logDebug(msg);
}
- static void logInfo(String msg) {
+ /** */
+ public static void logInfo(String msg) {
BrightLineFalsingManager.logInfo(msg);
}
- static void logError(String msg) {
+ /** */
+ public static void logError(String msg) {
BrightLineFalsingManager.logError(msg);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/PointerCountClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/PointerCountClassifier.java
index b726c3e2783f..dd5d8a8f557b 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/PointerCountClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/PointerCountClassifier.java
@@ -21,6 +21,8 @@ import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
import android.view.MotionEvent;
+import com.android.systemui.classifier.FalsingDataProvider;
+
import java.util.Locale;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ProximityClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/ProximityClassifier.java
index b128678af5db..3551c241e71e 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ProximityClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/ProximityClassifier.java
@@ -22,6 +22,7 @@ import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
import android.provider.DeviceConfig;
import android.view.MotionEvent;
+import com.android.systemui.classifier.FalsingDataProvider;
import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.sensors.ProximitySensor;
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/SingleTapClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/SingleTapClassifier.java
index 47708f4dd789..8c7648149e44 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/SingleTapClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/SingleTapClassifier.java
@@ -18,6 +18,8 @@ package com.android.systemui.classifier.brightline;
import android.view.MotionEvent;
+import com.android.systemui.classifier.FalsingDataProvider;
+
import java.util.List;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/TimeLimitedMotionEventBuffer.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/TimeLimitedMotionEventBuffer.java
index 92aa7c5b2f44..7430a1eda920 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/TimeLimitedMotionEventBuffer.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/TimeLimitedMotionEventBuffer.java
@@ -36,7 +36,7 @@ public class TimeLimitedMotionEventBuffer implements List<MotionEvent> {
private final LinkedList<MotionEvent> mMotionEvents;
private final long mMaxAgeMs;
- TimeLimitedMotionEventBuffer(long maxAgeMs) {
+ public TimeLimitedMotionEventBuffer(long maxAgeMs) {
super();
mMaxAgeMs = maxAgeMs;
mMotionEvents = new LinkedList<>();
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/TypeClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/TypeClassifier.java
index 5f1b37ae06d9..f62871f383b3 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/TypeClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/TypeClassifier.java
@@ -26,6 +26,8 @@ import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
import static com.android.systemui.classifier.Classifier.RIGHT_AFFORDANCE;
import static com.android.systemui.classifier.Classifier.UNLOCK;
+import com.android.systemui.classifier.FalsingDataProvider;
+
/**
* Ensure that the swipe direction generally matches that of the interaction type.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java
index a796f3c6d547..9ca77d364bc4 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java
@@ -25,6 +25,7 @@ import android.graphics.Point;
import android.provider.DeviceConfig;
import android.view.MotionEvent;
+import com.android.systemui.classifier.FalsingDataProvider;
import com.android.systemui.util.DeviceConfigProxy;
import java.util.ArrayList;
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 780bb5b01103..4d697005be7b 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -27,6 +27,7 @@ import com.android.systemui.BootCompleteCache;
import com.android.systemui.BootCompleteCacheImpl;
import com.android.systemui.appops.dagger.AppOpsModule;
import com.android.systemui.assist.AssistModule;
+import com.android.systemui.classifier.FalsingModule;
import com.android.systemui.controls.dagger.ControlsModule;
import com.android.systemui.demomode.dagger.DemoModeModule;
import com.android.systemui.doze.dagger.DozeComponent;
@@ -89,6 +90,7 @@ import dagger.Provides;
AssistModule.class,
ControlsModule.class,
DemoModeModule.class,
+ FalsingModule.class,
LogModule.class,
PeopleHubModule.class,
PowerModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFalsingManagerAdapter.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFalsingManagerAdapter.java
index 94b8ba305d0c..ef696a88548a 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFalsingManagerAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFalsingManagerAdapter.java
@@ -16,8 +16,8 @@
package com.android.systemui.doze;
+import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.doze.dagger.DozeScope;
-import com.android.systemui.plugins.FalsingManager;
import javax.inject.Inject;
@@ -27,16 +27,16 @@ import javax.inject.Inject;
@DozeScope
public class DozeFalsingManagerAdapter implements DozeMachine.Part {
- private final FalsingManager mFalsingManager;
+ private final FalsingCollector mFalsingCollector;
@Inject
- public DozeFalsingManagerAdapter(FalsingManager falsingManager) {
- mFalsingManager = falsingManager;
+ public DozeFalsingManagerAdapter(FalsingCollector falsingCollector) {
+ mFalsingCollector = falsingCollector;
}
@Override
public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
- mFalsingManager.setShowingAod(isAodMode(newState));
+ mFalsingCollector.setShowingAod(isAodMode(newState));
}
private boolean isAodMode(DozeMachine.State state) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index aea0dd0ee4b1..c6bfcbaae188 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -88,12 +88,12 @@ import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.SystemUI;
import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardService;
import com.android.systemui.keyguard.dagger.KeyguardModule;
import com.android.systemui.navigationbar.NavigationModeController;
-import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.statusbar.phone.BiometricUnlockController;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
@@ -223,7 +223,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
private boolean mBootSendUserPresent;
private boolean mShuttingDown;
private boolean mDozing;
- private final FalsingManager mFalsingManager;
+ private final FalsingCollector mFalsingCollector;
/** High level access to the power manager for WakeLocks */
private final PowerManager mPM;
@@ -715,7 +715,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
*/
public KeyguardViewMediator(
Context context,
- FalsingManager falsingManager,
+ FalsingCollector falsingCollector,
LockPatternUtils lockPatternUtils,
BroadcastDispatcher broadcastDispatcher,
Lazy<KeyguardViewController> statusBarKeyguardViewManagerLazy,
@@ -727,7 +727,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
NavigationModeController navigationModeController,
KeyguardDisplayManager keyguardDisplayManager) {
super(context);
- mFalsingManager = falsingManager;
+ mFalsingCollector = falsingCollector;
mLockPatternUtils = lockPatternUtils;
mBroadcastDispatcher = broadcastDispatcher;
mKeyguardViewControllerLazy = statusBarKeyguardViewManagerLazy;
@@ -1682,7 +1682,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
"KeyguardViewMediator#handleMessage START_KEYGUARD_EXIT_ANIM");
StartKeyguardExitAnimParams params = (StartKeyguardExitAnimParams) msg.obj;
handleStartKeyguardExitAnimation(params.startTime, params.fadeoutDuration);
- mFalsingManager.onSuccessfulUnlock();
+ mFalsingCollector.onSuccessfulUnlock();
Trace.endSection();
break;
case KEYGUARD_DONE_PENDING_TIMEOUT:
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
index e50fd6a96b5c..d7b5eea84c36 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -31,6 +31,8 @@ import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardViewController;
import com.android.keyguard.dagger.KeyguardStatusViewComponent;
import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.classifier.FalsingCollector;
+import com.android.systemui.classifier.FalsingModule;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.UiBackground;
@@ -39,7 +41,6 @@ import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.keyguard.FaceAuthScreenBrightnessController;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.navigationbar.NavigationModeController;
-import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.KeyguardLiftController;
@@ -59,7 +60,8 @@ import dagger.Provides;
/**
* Dagger Module providing {@link StatusBar}.
*/
-@Module(subcomponents = {KeyguardStatusViewComponent.class})
+@Module(subcomponents = {KeyguardStatusViewComponent.class},
+ includes = {FalsingModule.class})
public class KeyguardModule {
/**
* Provides our instance of KeyguardViewMediator which is considered optional.
@@ -68,7 +70,7 @@ public class KeyguardModule {
@SysUISingleton
public static KeyguardViewMediator newKeyguardViewMediator(
Context context,
- FalsingManager falsingManager,
+ FalsingCollector falsingCollector,
LockPatternUtils lockPatternUtils,
BroadcastDispatcher broadcastDispatcher,
Lazy<KeyguardViewController> statusBarKeyguardViewManagerLazy,
@@ -83,7 +85,7 @@ public class KeyguardModule {
KeyguardDisplayManager keyguardDisplayManager) {
return new KeyguardViewMediator(
context,
- falsingManager,
+ falsingCollector,
lockPatternUtils,
broadcastDispatcher,
statusBarKeyguardViewManagerLazy,
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
index 5eb6687f0b81..935352665314 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
@@ -12,6 +12,7 @@ import android.view.ViewGroup
import android.widget.LinearLayout
import androidx.annotation.VisibleForTesting
import com.android.systemui.R
+import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.plugins.ActivityStarter
@@ -44,6 +45,7 @@ class MediaCarouselController @Inject constructor(
@Main executor: DelayableExecutor,
private val mediaManager: MediaDataManager,
configurationController: ConfigurationController,
+ falsingCollector: FalsingCollector,
falsingManager: FalsingManager
) {
/**
@@ -156,7 +158,7 @@ class MediaCarouselController @Inject constructor(
pageIndicator = mediaFrame.requireViewById(R.id.media_page_indicator)
mediaCarouselScrollHandler = MediaCarouselScrollHandler(mediaCarousel, pageIndicator,
executor, mediaManager::onSwipeToDismiss, this::updatePageIndicatorLocation,
- this::closeGuts, falsingManager)
+ this::closeGuts, falsingCollector, falsingManager)
isRtl = context.resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_RTL
inflateSettingsButton()
mediaContent = mediaCarousel.requireViewById(R.id.media_carousel)
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt
index cb14f31abd16..bb6fbfab4c90 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt
@@ -31,6 +31,7 @@ import com.android.systemui.Gefingerpoken
import com.android.systemui.qs.PageIndicator
import com.android.systemui.R
import com.android.systemui.classifier.Classifier.NOTIFICATION_DISMISS
+import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.plugins.FalsingManager
import com.android.wm.shell.animation.PhysicsAnimator
import com.android.systemui.util.concurrency.DelayableExecutor
@@ -58,6 +59,7 @@ class MediaCarouselScrollHandler(
private val dismissCallback: () -> Unit,
private var translationChangedListener: () -> Unit,
private val closeGuts: () -> Unit,
+ private val falsingCollector: FalsingCollector,
private val falsingManager: FalsingManager
) {
/**
@@ -162,7 +164,7 @@ class MediaCarouselScrollHandler(
override fun onDown(e: MotionEvent?): Boolean {
if (falsingProtectionNeeded) {
- falsingManager.onNotificationStartDismissing()
+ falsingCollector.onNotificationStartDismissing()
}
return false
}
@@ -258,7 +260,7 @@ class MediaCarouselScrollHandler(
private fun onTouch(motionEvent: MotionEvent): Boolean {
val isUp = motionEvent.action == MotionEvent.ACTION_UP
if (isUp && falsingProtectionNeeded) {
- falsingManager.onNotificationStopDismissing()
+ falsingCollector.onNotificationStopDismissing()
}
if (gestureDetector.onTouchEvent(motionEvent)) {
if (isUp) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
index d7a2975a4b04..0f0a9a2766f1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
@@ -134,7 +134,7 @@ public class ScreenRecordTile extends QSTileImpl<QSTile.BooleanState>
getHost().collapsePanels();
Intent intent = mController.getPromptIntent();
ActivityStarter.OnDismissAction dismissAction = () -> {
- mContext.startActivity(intent);
+ mHost.getUserContext().startActivity(intent);
return false;
};
mKeyguardDismissUtil.executeWhenUnlocked(dismissAction, false);
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
index 10a44ddb17f2..7ca82774f737 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
@@ -54,14 +54,31 @@ public class RecordingController
private CountDownTimer mCountDownTimer = null;
private BroadcastDispatcher mBroadcastDispatcher;
+ protected static final String INTENT_UPDATE_STATE =
+ "com.android.systemui.screenrecord.UPDATE_STATE";
+ protected static final String EXTRA_STATE = "extra_state";
+
private ArrayList<RecordingStateChangeCallback> mListeners = new ArrayList<>();
@VisibleForTesting
protected final BroadcastReceiver mUserChangeReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- if (mStopIntent != null) {
- stopRecording();
+ stopRecording();
+ }
+ };
+
+ @VisibleForTesting
+ protected final BroadcastReceiver mStateChangeReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent != null && INTENT_UPDATE_STATE.equals(intent.getAction())) {
+ if (intent.hasExtra(EXTRA_STATE)) {
+ boolean state = intent.getBooleanExtra(EXTRA_STATE, false);
+ updateState(state);
+ } else {
+ Log.e(TAG, "Received update intent with no state");
+ }
}
}
};
@@ -118,6 +135,10 @@ public class RecordingController
IntentFilter userFilter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
mBroadcastDispatcher.registerReceiver(mUserChangeReceiver, userFilter, null,
UserHandle.ALL);
+
+ IntentFilter stateFilter = new IntentFilter(INTENT_UPDATE_STATE);
+ mBroadcastDispatcher.registerReceiver(mStateChangeReceiver, stateFilter, null,
+ UserHandle.ALL);
Log.d(TAG, "sent start intent");
} catch (PendingIntent.CanceledException e) {
Log.e(TAG, "Pending intent was cancelled: " + e.getMessage());
@@ -174,7 +195,6 @@ public class RecordingController
} catch (PendingIntent.CanceledException e) {
Log.e(TAG, "Error stopping: " + e.getMessage());
}
- mBroadcastDispatcher.unregisterReceiver(mUserChangeReceiver);
}
/**
@@ -182,6 +202,11 @@ public class RecordingController
* @param isRecording
*/
public synchronized void updateState(boolean isRecording) {
+ if (!isRecording && mIsRecording) {
+ // Unregister receivers if we have stopped recording
+ mBroadcastDispatcher.unregisterReceiver(mUserChangeReceiver);
+ mBroadcastDispatcher.unregisterReceiver(mStateChangeReceiver);
+ }
mIsRecording = isRecording;
for (RecordingStateChangeCallback cb : mListeners) {
if (isRecording) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
index 3bf118d1f39f..197582104f8e 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
@@ -69,6 +69,7 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis
private static final String ACTION_STOP_NOTIF =
"com.android.systemui.screenrecord.STOP_FROM_NOTIF";
private static final String ACTION_SHARE = "com.android.systemui.screenrecord.SHARE";
+ private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
private final RecordingController mController;
private final KeyguardDismissUtil mKeyguardDismissUtil;
@@ -120,8 +121,8 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis
String action = intent.getAction();
Log.d(TAG, "onStartCommand " + action);
- int mCurrentUserId = mUserContextTracker.getUserContext().getUserId();
- UserHandle currentUser = new UserHandle(mCurrentUserId);
+ int currentUserId = mUserContextTracker.getUserContext().getUserId();
+ UserHandle currentUser = new UserHandle(currentUserId);
switch (action) {
case ACTION_START:
mAudioSource = ScreenRecordingAudioSource
@@ -137,11 +138,22 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis
mRecorder = new ScreenMediaRecorder(
mUserContextTracker.getUserContext(),
- mCurrentUserId,
+ currentUserId,
mAudioSource,
this
);
- startRecording();
+
+ if (startRecording()) {
+ updateState(true);
+ createRecordingNotification();
+ mUiEventLogger.log(Events.ScreenRecordEvent.SCREEN_RECORD_START);
+ } else {
+ updateState(false);
+ createErrorNotification();
+ stopForeground(true);
+ stopSelf();
+ return Service.START_NOT_STICKY;
+ }
break;
case ACTION_STOP_NOTIF:
@@ -201,22 +213,63 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis
return mRecorder;
}
+ private void updateState(boolean state) {
+ int userId = mUserContextTracker.getUserContext().getUserId();
+ if (userId == UserHandle.USER_SYSTEM) {
+ // Main user has a reference to the correct controller, so no need to use a broadcast
+ mController.updateState(state);
+ } else {
+ Intent intent = new Intent(RecordingController.INTENT_UPDATE_STATE);
+ intent.putExtra(RecordingController.EXTRA_STATE, state);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ sendBroadcast(intent, PERMISSION_SELF);
+ }
+ }
+
/**
* Begin the recording session
+ * @return true if successful, false if something went wrong
*/
- private void startRecording() {
+ private boolean startRecording() {
try {
getRecorder().start();
- mController.updateState(true);
- createRecordingNotification();
- mUiEventLogger.log(Events.ScreenRecordEvent.SCREEN_RECORD_START);
- } catch (IOException | RemoteException | IllegalStateException e) {
- Toast.makeText(this,
- R.string.screenrecord_start_error, Toast.LENGTH_LONG)
- .show();
+ return true;
+ } catch (IOException | RemoteException | RuntimeException e) {
+ showErrorToast(R.string.screenrecord_start_error);
e.printStackTrace();
- mController.updateState(false);
}
+ return false;
+ }
+
+ /**
+ * Simple error notification, needed since startForeground must be called to avoid errors
+ */
+ @VisibleForTesting
+ protected void createErrorNotification() {
+ Resources res = getResources();
+ NotificationChannel channel = new NotificationChannel(
+ CHANNEL_ID,
+ getString(R.string.screenrecord_name),
+ NotificationManager.IMPORTANCE_DEFAULT);
+ channel.setDescription(getString(R.string.screenrecord_channel_description));
+ channel.enableVibration(true);
+ mNotificationManager.createNotificationChannel(channel);
+
+ Bundle extras = new Bundle();
+ extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
+ res.getString(R.string.screenrecord_name));
+ String notificationTitle = res.getString(R.string.screenrecord_start_error);
+
+ Notification.Builder builder = new Notification.Builder(this, CHANNEL_ID)
+ .setSmallIcon(R.drawable.ic_screenrecord)
+ .setContentTitle(notificationTitle)
+ .addExtras(extras);
+ startForeground(NOTIFICATION_RECORDING_ID, builder.build());
+ }
+
+ @VisibleForTesting
+ protected void showErrorToast(int stringId) {
+ Toast.makeText(this, stringId, Toast.LENGTH_LONG).show();
}
@VisibleForTesting
@@ -247,6 +300,7 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis
.setColorized(true)
.setColor(getResources().getColor(R.color.GM2_red_700))
.setOngoing(true)
+ .setShowForegroundImmediately(true)
.setContentIntent(
PendingIntent.getService(this, REQUEST_CODE, stopIntent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE))
@@ -326,7 +380,7 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis
} else {
Log.e(TAG, "stopRecording called, but recorder was null");
}
- mController.updateState(false);
+ updateState(false);
}
private void saveRecording(int userId) {
@@ -344,8 +398,7 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis
}
} catch (IOException e) {
Log.e(TAG, "Error saving screen recording: " + e.getMessage());
- Toast.makeText(this, R.string.screenrecord_delete_error, Toast.LENGTH_LONG)
- .show();
+ showErrorToast(R.string.screenrecord_delete_error);
} finally {
mNotificationManager.cancelAsUser(null, NOTIFICATION_PROCESSING_ID, currentUser);
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
index 45564b0bfa6b..9037192e2ddc 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
@@ -94,7 +94,7 @@ public class ScreenMediaRecorder {
mAudioSource = audioSource;
}
- private void prepare() throws IOException, RemoteException {
+ private void prepare() throws IOException, RemoteException, RuntimeException {
//Setup media projection
IBinder b = ServiceManager.getService(MEDIA_PROJECTION_SERVICE);
IMediaProjectionManager mediaService =
@@ -257,7 +257,7 @@ public class ScreenMediaRecorder {
/**
* Start screen recording
*/
- void start() throws IOException, RemoteException, IllegalStateException {
+ void start() throws IOException, RemoteException, RuntimeException {
Log.d(TAG, "start recording");
prepare();
mMediaRecorder.start();
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
index 672f82c2a583..2c82bcb24ad0 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -43,6 +43,7 @@ import android.view.WindowManager;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.util.ScreenshotHelper;
+import com.android.systemui.R;
import com.android.systemui.shared.recents.utilities.BitmapUtil;
import java.util.function.Consumer;
@@ -55,6 +56,7 @@ public class TakeScreenshotService extends Service {
private final ScreenshotController mScreenshot;
private final UserManager mUserManager;
private final UiEventLogger mUiEventLogger;
+ private final ScreenshotNotificationsController mNotificationsController;
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@@ -90,6 +92,8 @@ public class TakeScreenshotService extends Service {
// animation and error notification.
if (!mUserManager.isUserUnlocked()) {
Log.w(TAG, "Skipping screenshot because storage is locked!");
+ mNotificationsController.notifyScreenshotError(
+ R.string.screenshot_failed_to_save_user_locked_text);
post(() -> uriConsumer.accept(null));
post(onComplete);
return;
@@ -125,11 +129,15 @@ public class TakeScreenshotService extends Service {
};
@Inject
- public TakeScreenshotService(ScreenshotController screenshotController, UserManager userManager,
- UiEventLogger uiEventLogger) {
+ public TakeScreenshotService(
+ ScreenshotController screenshotController,
+ UserManager userManager,
+ UiEventLogger uiEventLogger,
+ ScreenshotNotificationsController notificationsController) {
mScreenshot = screenshotController;
mUserManager = userManager;
mUiEventLogger = uiEventLogger;
+ mNotificationsController = notificationsController;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
index e61e05a7dc2f..7ef88bb0c2c8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
@@ -31,6 +31,7 @@ import com.android.systemui.ExpandHelper;
import com.android.systemui.Gefingerpoken;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.statusbar.notification.row.ExpandableView;
@@ -46,6 +47,7 @@ public class DragDownHelper implements Gefingerpoken {
private static final int SPRING_BACK_ANIMATION_LENGTH_MS = 375;
private int mMinDragDistance;
+ private final FalsingManager mFalsingManager;
private ExpandHelper.Callback mCallback;
private float mInitialTouchX;
private float mInitialTouchY;
@@ -58,20 +60,21 @@ public class DragDownHelper implements Gefingerpoken {
private boolean mDraggedFarEnough;
private ExpandableView mStartingChild;
private float mLastHeight;
- private FalsingManager mFalsingManager;
+ private FalsingCollector mFalsingCollector;
public DragDownHelper(Context context, View host, ExpandHelper.Callback callback,
- DragDownCallback dragDownCallback,
- FalsingManager falsingManager) {
+ DragDownCallback dragDownCallback, FalsingManager falsingManager,
+ FalsingCollector falsingCollector) {
mMinDragDistance = context.getResources().getDimensionPixelSize(
R.dimen.keyguard_drag_down_min_distance);
+ mFalsingManager = falsingManager;
final ViewConfiguration configuration = ViewConfiguration.get(context);
mTouchSlop = configuration.getScaledTouchSlop();
mSlopMultiplier = configuration.getScaledAmbiguousGestureMultiplier();
mCallback = callback;
mDragDownCallback = dragDownCallback;
mHost = host;
- mFalsingManager = falsingManager;
+ mFalsingCollector = falsingCollector;
}
@Override
@@ -96,7 +99,7 @@ public class DragDownHelper implements Gefingerpoken {
? mTouchSlop * mSlopMultiplier
: mTouchSlop;
if (h > touchSlop && h > Math.abs(x - mInitialTouchX)) {
- mFalsingManager.onNotificatonStartDraggingDown();
+ mFalsingCollector.onNotificationStartDraggingDown();
mDraggingDown = true;
captureStartingChild(mInitialTouchX, mInitialTouchY);
mInitialTouchY = y;
@@ -229,7 +232,7 @@ public class DragDownHelper implements Gefingerpoken {
}
private void stopDragging() {
- mFalsingManager.onNotificatonStopDraggingDown();
+ mFalsingCollector.onNotificationStopDraggingDown();
if (mStartingChild != null) {
cancelExpansion(mStartingChild);
mStartingChild = null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
index 6fa3633acc43..b7343f67a86d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
@@ -31,6 +31,7 @@ import com.android.systemui.Gefingerpoken
import com.android.systemui.Interpolators
import com.android.systemui.R
import com.android.systemui.classifier.Classifier.NOTIFICATION_DRAG_DOWN
+import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
@@ -57,7 +58,8 @@ constructor(
private val headsUpManager: HeadsUpManagerPhone,
private val roundnessManager: NotificationRoundnessManager,
private val statusBarStateController: StatusBarStateController,
- private val falsingManager: FalsingManager
+ private val falsingManager: FalsingManager,
+ private val falsingCollector: FalsingCollector
) : Gefingerpoken {
companion object {
private val RUBBERBAND_FACTOR_STATIC = 0.25f
@@ -148,7 +150,7 @@ constructor(
MotionEvent.ACTION_MOVE -> {
val h = y - mInitialTouchY
if (h > mTouchSlop && h > Math.abs(x - mInitialTouchX)) {
- falsingManager.onStartExpandingFromPulse()
+ falsingCollector.onStartExpandingFromPulse()
isExpanding = true
captureStartingChild(mInitialTouchX, mInitialTouchY)
mInitialTouchY = y
@@ -301,7 +303,7 @@ constructor(
private fun cancelExpansion() {
isExpanding = false
- falsingManager.onExpansionFromPulseStopped()
+ falsingCollector.onExpansionFromPulseStopped()
if (mStartingChild != null) {
reset(mStartingChild!!)
mStartingChild = null
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java
index 0b79387fac77..50bbc38eddf3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java
@@ -22,6 +22,7 @@ import android.view.View;
import android.view.accessibility.AccessibilityManager;
import com.android.systemui.Gefingerpoken;
+import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.statusbar.phone.NotificationTapHelper;
import com.android.systemui.util.ViewController;
@@ -36,6 +37,7 @@ public class ActivatableNotificationViewController
private final ExpandableOutlineViewController mExpandableOutlineViewController;
private final AccessibilityManager mAccessibilityManager;
private final FalsingManager mFalsingManager;
+ private final FalsingCollector mFalsingCollector;
private final NotificationTapHelper mNotificationTapHelper;
private final TouchHandler mTouchHandler = new TouchHandler();
@@ -45,17 +47,19 @@ public class ActivatableNotificationViewController
public ActivatableNotificationViewController(ActivatableNotificationView view,
NotificationTapHelper.Factory notificationTapHelpFactory,
ExpandableOutlineViewController expandableOutlineViewController,
- AccessibilityManager accessibilityManager, FalsingManager falsingManager) {
+ AccessibilityManager accessibilityManager, FalsingManager falsingManager,
+ FalsingCollector falsingCollector) {
super(view);
mExpandableOutlineViewController = expandableOutlineViewController;
mAccessibilityManager = accessibilityManager;
mFalsingManager = falsingManager;
+ mFalsingCollector = falsingCollector;
mNotificationTapHelper = notificationTapHelpFactory.create(
(active) -> {
if (active) {
mView.makeActive();
- mFalsingManager.onNotificationActive();
+ mFalsingCollector.onNotificationActive();
} else {
mView.makeInactive(true /* animate */);
}
@@ -64,7 +68,7 @@ public class ActivatableNotificationViewController
mView.setOnActivatedListener(new ActivatableNotificationView.OnActivatedListener() {
@Override
public void onActivated(ActivatableNotificationView view) {
- mFalsingManager.onNotificationActive();
+ mFalsingCollector.onNotificationActive();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 5682c88edc63..5ed17f1ee07f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -43,7 +43,6 @@ import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
-import android.provider.Settings;
import android.service.notification.StatusBarNotification;
import android.util.ArraySet;
import android.util.AttributeSet;
@@ -74,7 +73,7 @@ import com.android.internal.widget.MessagingLayout;
import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
@@ -213,7 +212,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
private NotificationGuts mGuts;
private NotificationEntry mEntry;
private String mAppName;
- private FalsingManager mFalsingManager;
+ private FalsingCollector mFalsingCollector;
/**
* Whether or not the notification is using the heads up view and should peek from the top.
@@ -1584,7 +1583,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
OnExpandClickListener onExpandClickListener,
NotificationMediaManager notificationMediaManager,
CoordinateOnClickListener onFeedbackClickListener,
- FalsingManager falsingManager,
+ FalsingCollector falsingCollector,
StatusBarStateController statusBarStateController,
PeopleNotificationIdentifier peopleNotificationIdentifier,
OnUserInteractionCallback onUserInteractionCallback,
@@ -1609,7 +1608,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
mOnExpandClickListener = onExpandClickListener;
mMediaManager = notificationMediaManager;
setOnFeedbackClickListener(onFeedbackClickListener);
- mFalsingManager = falsingManager;
+ mFalsingCollector = falsingCollector;
mStatusBarStateController = statusBarStateController;
mPeopleNotificationIdentifier = peopleNotificationIdentifier;
@@ -2176,7 +2175,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
* @param allowChildExpansion whether a call to this method allows expanding children
*/
public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
- mFalsingManager.setNotificationExpanded();
+ mFalsingCollector.setNotificationExpanded();
if (mIsSummaryWithChildren && !shouldShowPublic() && allowChildExpansion
&& !mChildrenContainer.showingAsLowPriority()) {
final boolean wasExpanded = mGroupExpansionManager.isGroupExpanded(mEntry);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
index cb2af54a25cb..0d0e97eae519 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
@@ -25,7 +25,7 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull;
-import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.plugins.PluginManager;
@@ -78,7 +78,7 @@ public class ExpandableNotificationRowController implements NodeController {
private final ExpandableNotificationRow.CoordinateOnClickListener mOnFeedbackClickListener;
private final NotificationGutsManager mNotificationGutsManager;
private final OnUserInteractionCallback mOnUserInteractionCallback;
- private final FalsingManager mFalsingManager;
+ private final FalsingCollector mFalsingCollector;
private final boolean mAllowLongPress;
private final PeopleNotificationIdentifier mPeopleNotificationIdentifier;
private final Optional<BubblesManager> mBubblesManagerOptional;
@@ -104,7 +104,7 @@ public class ExpandableNotificationRowController implements NodeController {
NotificationGutsManager notificationGutsManager,
@Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowLongPress,
OnUserInteractionCallback onUserInteractionCallback,
- FalsingManager falsingManager,
+ FalsingCollector falsingCollector,
PeopleNotificationIdentifier peopleNotificationIdentifier,
Optional<BubblesManager> bubblesManagerOptional) {
mView = view;
@@ -127,7 +127,7 @@ public class ExpandableNotificationRowController implements NodeController {
mOnUserInteractionCallback = onUserInteractionCallback;
mOnFeedbackClickListener = mNotificationGutsManager::openGuts;
mAllowLongPress = allowLongPress;
- mFalsingManager = falsingManager;
+ mFalsingCollector = falsingCollector;
mPeopleNotificationIdentifier = peopleNotificationIdentifier;
mBubblesManagerOptional = bubblesManagerOptional;
}
@@ -150,7 +150,7 @@ public class ExpandableNotificationRowController implements NodeController {
mOnExpandClickListener,
mMediaManager,
mOnFeedbackClickListener,
- mFalsingManager,
+ mFalsingCollector,
mStatusBarStateController,
mPeopleNotificationIdentifier,
mOnUserInteractionCallback,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 006d8da91941..9d4665a5eeca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -60,10 +60,10 @@ import com.android.systemui.ExpandHelper;
import com.android.systemui.Gefingerpoken;
import com.android.systemui.R;
import com.android.systemui.SwipeHelper;
+import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.media.KeyguardMediaController;
-import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
@@ -143,7 +143,7 @@ public class NotificationStackScrollLayoutController {
private final ConfigurationController mConfigurationController;
private final ZenModeController mZenModeController;
private final MetricsLogger mMetricsLogger;
- private final FalsingManager mFalsingManager;
+ private final FalsingCollector mFalsingCollector;
private final Resources mResources;
private final NotificationSwipeHelper.Builder mNotificationSwipeHelperBuilder;
private final ScrimController mScrimController;
@@ -361,7 +361,7 @@ public class NotificationStackScrollLayoutController {
@Override
public void onDragCancelled(View v) {
- mFalsingManager.onNotificationStopDismissing();
+ mFalsingCollector.onNotificationStopDismissing();
}
/**
@@ -405,8 +405,8 @@ public class NotificationStackScrollLayoutController {
}
mView.addSwipedOutView(view);
- mFalsingManager.onNotificationDismissed();
- if (mFalsingManager.shouldEnforceBouncer()) {
+ mFalsingCollector.onNotificationDismissed();
+ if (mFalsingCollector.shouldEnforceBouncer()) {
mStatusBar.executeRunnableDismissingKeyguard(
null,
null /* cancelAction */,
@@ -448,7 +448,7 @@ public class NotificationStackScrollLayoutController {
@Override
public void onBeginDrag(View v) {
- mFalsingManager.onNotificationStartDismissing();
+ mFalsingCollector.onNotificationStartDismissing();
mView.onSwipeBegin();
}
@@ -550,7 +550,7 @@ public class NotificationStackScrollLayoutController {
SysuiColorExtractor colorExtractor,
NotificationLockscreenUserManager lockscreenUserManager,
MetricsLogger metricsLogger,
- FalsingManager falsingManager,
+ FalsingCollector falsingCollector,
@Main Resources resources,
NotificationSwipeHelper.Builder notificationSwipeHelperBuilder,
StatusBar statusBar,
@@ -584,7 +584,7 @@ public class NotificationStackScrollLayoutController {
mColorExtractor = colorExtractor;
mLockscreenUserManager = lockscreenUserManager;
mMetricsLogger = metricsLogger;
- mFalsingManager = falsingManager;
+ mFalsingCollector = falsingCollector;
mResources = resources;
mNotificationSwipeHelperBuilder = notificationSwipeHelperBuilder;
mStatusBar = statusBar;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 80cb289a3c0d..9854f5450df1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -39,9 +39,9 @@ import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.keyguard.ViewMediatorCallback;
import com.android.keyguard.dagger.KeyguardBouncerComponent;
import com.android.systemui.DejankUtils;
+import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.dagger.qualifiers.RootView;
import com.android.systemui.keyguard.DismissCallbackRegistry;
-import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -65,7 +65,7 @@ public class KeyguardBouncer {
protected final Context mContext;
protected final ViewMediatorCallback mCallback;
protected final ViewGroup mContainer;
- private final FalsingManager mFalsingManager;
+ private final FalsingCollector mFalsingCollector;
private final DismissCallbackRegistry mDismissCallbackRegistry;
private final Handler mHandler;
private final List<BouncerExpansionCallback> mExpansionCallbacks = new ArrayList<>();
@@ -100,7 +100,7 @@ public class KeyguardBouncer {
private KeyguardBouncer(Context context, ViewMediatorCallback callback,
ViewGroup container,
- DismissCallbackRegistry dismissCallbackRegistry, FalsingManager falsingManager,
+ DismissCallbackRegistry dismissCallbackRegistry, FalsingCollector falsingCollector,
BouncerExpansionCallback expansionCallback,
KeyguardStateController keyguardStateController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
@@ -111,7 +111,7 @@ public class KeyguardBouncer {
mCallback = callback;
mContainer = container;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
- mFalsingManager = falsingManager;
+ mFalsingCollector = falsingCollector;
mDismissCallbackRegistry = dismissCallbackRegistry;
mHandler = handler;
mKeyguardStateController = keyguardStateController;
@@ -203,7 +203,7 @@ public class KeyguardBouncer {
* will never be notified and its internal state will be out of sync.
*/
private void onFullyShown() {
- mFalsingManager.onBouncerShown();
+ mFalsingCollector.onBouncerShown();
if (mKeyguardViewController == null) {
Log.wtf(TAG, "onFullyShown when view was null");
} else {
@@ -223,7 +223,7 @@ public class KeyguardBouncer {
if (mRoot != null) {
mRoot.setVisibility(View.INVISIBLE);
}
- mFalsingManager.onBouncerHidden();
+ mFalsingCollector.onBouncerHidden();
DejankUtils.postAfterTraversal(mResetRunnable);
}
@@ -290,7 +290,7 @@ public class KeyguardBouncer {
mDismissCallbackRegistry.notifyDismissCancelled();
}
mIsScrimmed = false;
- mFalsingManager.onBouncerHidden();
+ mFalsingCollector.onBouncerHidden();
mCallback.onBouncerVisiblityChanged(false /* shown */);
cancelShowRunnable();
if (mKeyguardViewController != null) {
@@ -327,7 +327,7 @@ public class KeyguardBouncer {
public void reset() {
cancelShowRunnable();
inflateView();
- mFalsingManager.onBouncerHidden();
+ mFalsingCollector.onBouncerHidden();
}
public void onScreenTurnedOff() {
@@ -541,7 +541,7 @@ public class KeyguardBouncer {
private final Context mContext;
private final ViewMediatorCallback mCallback;
private final DismissCallbackRegistry mDismissCallbackRegistry;
- private final FalsingManager mFalsingManager;
+ private final FalsingCollector mFalsingCollector;
private final KeyguardStateController mKeyguardStateController;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final KeyguardBypassController mKeyguardBypassController;
@@ -551,7 +551,7 @@ public class KeyguardBouncer {
@Inject
public Factory(Context context, ViewMediatorCallback callback,
- DismissCallbackRegistry dismissCallbackRegistry, FalsingManager falsingManager,
+ DismissCallbackRegistry dismissCallbackRegistry, FalsingCollector falsingCollector,
KeyguardStateController keyguardStateController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
KeyguardBypassController keyguardBypassController, Handler handler,
@@ -560,7 +560,7 @@ public class KeyguardBouncer {
mContext = context;
mCallback = callback;
mDismissCallbackRegistry = dismissCallbackRegistry;
- mFalsingManager = falsingManager;
+ mFalsingCollector = falsingCollector;
mKeyguardStateController = keyguardStateController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mKeyguardBypassController = keyguardBypassController;
@@ -572,7 +572,7 @@ public class KeyguardBouncer {
public KeyguardBouncer create(@RootView ViewGroup container,
BouncerExpansionCallback expansionCallback) {
return new KeyguardBouncer(mContext, mCallback, container,
- mDismissCallbackRegistry, mFalsingManager, expansionCallback,
+ mDismissCallbackRegistry, mFalsingCollector, expansionCallback,
mKeyguardStateController, mKeyguardUpdateMonitor,
mKeyguardBypassController, mHandler, mKeyguardSecurityModel,
mKeyguardBouncerComponentFactory);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 6b8881168e4e..f7139aa2acce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -79,6 +79,7 @@ import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.classifier.Classifier;
+import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.dagger.qualifiers.DisplayId;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.doze.DozeLog;
@@ -364,7 +365,8 @@ public class NotificationPanelViewController extends PanelViewController {
private boolean mHeadsUpAnimatingAway;
private boolean mLaunchingAffordance;
private boolean mAffordanceHasPreview;
- private FalsingManager mFalsingManager;
+ private final FalsingManager mFalsingManager;
+ private final FalsingCollector mFalsingCollector;
private String mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE;
private Runnable mHeadsUpExistenceChangedRunnable = () -> {
@@ -502,7 +504,7 @@ public class NotificationPanelViewController extends PanelViewController {
NotificationWakeUpCoordinator coordinator, PulseExpansionHandler pulseExpansionHandler,
DynamicPrivacyController dynamicPrivacyController,
KeyguardBypassController bypassController, FalsingManager falsingManager,
- ShadeController shadeController,
+ FalsingCollector falsingCollector, ShadeController shadeController,
NotificationLockscreenUserManager notificationLockscreenUserManager,
NotificationEntryManager notificationEntryManager,
KeyguardStateController keyguardStateController,
@@ -543,6 +545,7 @@ public class NotificationPanelViewController extends PanelViewController {
mView.setWillNotDraw(!DEBUG);
mInjectionInflationController = injectionInflationController;
mFalsingManager = falsingManager;
+ mFalsingCollector = falsingCollector;
mPowerManager = powerManager;
mWakeUpCoordinator = coordinator;
mAccessibilityManager = accessibilityManager;
@@ -1426,7 +1429,7 @@ public class NotificationPanelViewController extends PanelViewController {
private void handleQsDown(MotionEvent event) {
if (event.getActionMasked() == MotionEvent.ACTION_DOWN && shouldQuickSettingsIntercept(
event.getX(), event.getY(), -1)) {
- mFalsingManager.onQsDown();
+ mFalsingCollector.onQsDown();
mQsTracking = true;
onQsExpansionStarted();
mInitialHeightOnTouch = mQsExpansionHeight;
@@ -1606,7 +1609,7 @@ public class NotificationPanelViewController extends PanelViewController {
mQsExpanded = expanded;
updateQsState();
requestPanelHeightUpdate();
- mFalsingManager.setQsExpanded(expanded);
+ mFalsingCollector.setQsExpanded(expanded);
mStatusBar.setQsExpanded(expanded);
mNotificationContainerParent.setQsExpanded(expanded);
mPulseExpansionHandler.setQsExpanded(expanded);
@@ -1743,7 +1746,7 @@ public class NotificationPanelViewController extends PanelViewController {
}
if (!mFalsingManager.isUnlockingDisabled() && mQsFullyExpanded
- && mFalsingManager.shouldEnforceBouncer()) {
+ && mFalsingCollector.shouldEnforceBouncer()) {
mStatusBar.executeRunnableDismissingKeyguard(null, null /* cancelAction */,
false /* dismissShade */, true /* afterKeyguardGone */, false /* deferred */);
}
@@ -2404,7 +2407,7 @@ public class NotificationPanelViewController extends PanelViewController {
@Override
protected void onTrackingStarted() {
- mFalsingManager.onTrackingStarted(!mKeyguardStateController.canDismissLockScreen());
+ mFalsingCollector.onTrackingStarted(!mKeyguardStateController.canDismissLockScreen());
super.onTrackingStarted();
if (mQsFullyExpanded) {
mQsExpandImmediate = true;
@@ -2418,7 +2421,7 @@ public class NotificationPanelViewController extends PanelViewController {
@Override
protected void onTrackingStopped(boolean expand) {
- mFalsingManager.onTrackingStopped();
+ mFalsingCollector.onTrackingStopped();
super.onTrackingStopped(expand);
if (expand) {
mNotificationStackScrollLayoutController.setOverScrolledPixels(0.0f, true /* onTop */,
@@ -3365,8 +3368,8 @@ public class NotificationPanelViewController extends PanelViewController {
if (start) {
mLockscreenGestureLogger.write(MetricsEvent.ACTION_LS_DIALER, lengthDp, velocityDp);
mLockscreenGestureLogger.log(LockscreenUiEvent.LOCKSCREEN_DIALER);
- mFalsingManager.onLeftAffordanceOn();
- if (mFalsingManager.shouldEnforceBouncer()) {
+ mFalsingCollector.onLeftAffordanceOn();
+ if (mFalsingCollector.shouldEnforceBouncer()) {
mStatusBar.executeRunnableDismissingKeyguard(
() -> mKeyguardBottomArea.launchLeftAffordance(), null,
true /* dismissShade */, false /* afterKeyguardGone */,
@@ -3381,8 +3384,8 @@ public class NotificationPanelViewController extends PanelViewController {
MetricsEvent.ACTION_LS_CAMERA, lengthDp, velocityDp);
mLockscreenGestureLogger.log(LockscreenUiEvent.LOCKSCREEN_CAMERA);
}
- mFalsingManager.onCameraOn();
- if (mFalsingManager.shouldEnforceBouncer()) {
+ mFalsingCollector.onCameraOn();
+ if (mFalsingCollector.shouldEnforceBouncer()) {
mStatusBar.executeRunnableDismissingKeyguard(
() -> mKeyguardBottomArea.launchCamera(mLastCameraLaunchSource), null,
true /* dismissShade */, false /* afterKeyguardGone */,
@@ -3413,7 +3416,7 @@ public class NotificationPanelViewController extends PanelViewController {
@Override
public void onSwipingStarted(boolean rightIcon) {
- mFalsingManager.onAffordanceSwipingStarted(rightIcon);
+ mFalsingCollector.onAffordanceSwipingStarted(rightIcon);
boolean
camera =
mView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL ? !rightIcon
@@ -3428,7 +3431,7 @@ public class NotificationPanelViewController extends PanelViewController {
@Override
public void onSwipingAborted() {
- mFalsingManager.onAffordanceSwipingAborted();
+ mFalsingCollector.onAffordanceSwipingAborted();
mKeyguardBottomArea.unbindCameraPrewarmService(false /* launched */);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
index 3db3ab5a56c8..ba4fbb871b97 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
@@ -36,6 +36,7 @@ import android.view.ViewGroup;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.ExpandHelper;
import com.android.systemui.R;
+import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.dock.DockManager;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.plugins.FalsingManager;
@@ -73,6 +74,7 @@ public class NotificationShadeWindowViewController {
private final KeyguardBypassController mBypassController;
private final PluginManager mPluginManager;
private final FalsingManager mFalsingManager;
+ private final FalsingCollector mFalsingCollector;
private final TunerService mTunerService;
private final NotificationLockscreenUserManager mNotificationLockscreenUserManager;
private final NotificationEntryManager mNotificationEntryManager;
@@ -118,6 +120,7 @@ public class NotificationShadeWindowViewController {
DynamicPrivacyController dynamicPrivacyController,
KeyguardBypassController bypassController,
FalsingManager falsingManager,
+ FalsingCollector falsingCollector,
PluginManager pluginManager,
TunerService tunerService,
NotificationLockscreenUserManager notificationLockscreenUserManager,
@@ -140,6 +143,7 @@ public class NotificationShadeWindowViewController {
mDynamicPrivacyController = dynamicPrivacyController;
mBypassController = bypassController;
mFalsingManager = falsingManager;
+ mFalsingCollector = falsingCollector;
mPluginManager = pluginManager;
mTunerService = tunerService;
mNotificationLockscreenUserManager = notificationLockscreenUserManager;
@@ -234,7 +238,7 @@ public class NotificationShadeWindowViewController {
if (mTouchCancelled || mExpandAnimationRunning || mExpandAnimationPending) {
return false;
}
- mFalsingManager.onTouchEvent(ev, mView.getWidth(), mView.getHeight());
+ mFalsingCollector.onTouchEvent(ev, mView.getWidth(), mView.getHeight());
mGestureDetector.onTouchEvent(ev);
if (mBrightnessMirror != null
&& mBrightnessMirror.getVisibility() == View.VISIBLE) {
@@ -394,7 +398,7 @@ public class NotificationShadeWindowViewController {
setDragDownHelper(
new DragDownHelper(
mView.getContext(), mView, expandHelperCallback,
- dragDownCallback, mFalsingManager));
+ dragDownCallback, mFalsingManager, mFalsingCollector));
mDepthController.setRoot(mView);
mNotificationPanelViewController.addExpansionListener(mDepthController);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index e6ac7dcee8a7..c8c5a6331a3b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -147,6 +147,7 @@ import com.android.systemui.SystemUI;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.charging.WirelessChargingAnimation;
+import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.demomode.DemoMode;
@@ -384,6 +385,7 @@ public class StatusBar extends SystemUI implements DemoMode,
private final StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
private final DynamicPrivacyController mDynamicPrivacyController;
private final BypassHeadsUpNotifier mBypassHeadsUpNotifier;
+ private final FalsingCollector mFalsingCollector;
private final FalsingManager mFalsingManager;
private final BroadcastDispatcher mBroadcastDispatcher;
private final ConfigurationController mConfigurationController;
@@ -692,6 +694,7 @@ public class StatusBar extends SystemUI implements DemoMode,
DynamicPrivacyController dynamicPrivacyController,
BypassHeadsUpNotifier bypassHeadsUpNotifier,
FalsingManager falsingManager,
+ FalsingCollector falsingCollector,
BroadcastDispatcher broadcastDispatcher,
RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
NotificationGutsManager notificationGutsManager,
@@ -772,6 +775,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mStatusBarTouchableRegionManager = statusBarTouchableRegionManager;
mDynamicPrivacyController = dynamicPrivacyController;
mBypassHeadsUpNotifier = bypassHeadsUpNotifier;
+ mFalsingCollector = falsingCollector;
mFalsingManager = falsingManager;
mBroadcastDispatcher = broadcastDispatcher;
mRemoteInputQuickSettingsDisabler = remoteInputQuickSettingsDisabler;
@@ -1389,7 +1393,7 @@ public class StatusBar extends SystemUI implements DemoMode,
where.getLocationInWindow(mTmpInt2);
mWakeUpTouchLocation = new PointF(mTmpInt2[0] + where.getWidth() / 2,
mTmpInt2[1] + where.getHeight() / 2);
- mFalsingManager.onScreenOnFromTouch();
+ mFalsingCollector.onScreenOnFromTouch();
}
}
@@ -1648,7 +1652,7 @@ public class StatusBar extends SystemUI implements DemoMode,
return;
}
mReportRejectedTouch.setVisibility(mState == StatusBarState.KEYGUARD && !mDozing
- && mFalsingManager.isReportingEnabled() ? View.VISIBLE : View.INVISIBLE);
+ && mFalsingCollector.isReportingEnabled() ? View.VISIBLE : View.INVISIBLE);
}
/**
@@ -3685,7 +3689,7 @@ public class StatusBar extends SystemUI implements DemoMode,
}
public void onUnlockHintStarted() {
- mFalsingManager.onUnlockHintStarted();
+ mFalsingCollector.onUnlockHintStarted();
mKeyguardIndicationController.showTransientIndication(R.string.keyguard_unlock);
}
@@ -3695,17 +3699,17 @@ public class StatusBar extends SystemUI implements DemoMode,
}
public void onCameraHintStarted() {
- mFalsingManager.onCameraHintStarted();
+ mFalsingCollector.onCameraHintStarted();
mKeyguardIndicationController.showTransientIndication(R.string.camera_hint);
}
public void onVoiceAssistHintStarted() {
- mFalsingManager.onLeftAffordanceHintStarted();
+ mFalsingCollector.onLeftAffordanceHintStarted();
mKeyguardIndicationController.showTransientIndication(R.string.voice_hint);
}
public void onPhoneHintStarted() {
- mFalsingManager.onLeftAffordanceHintStarted();
+ mFalsingCollector.onLeftAffordanceHintStarted();
mKeyguardIndicationController.showTransientIndication(R.string.phone_hint);
}
@@ -3756,7 +3760,7 @@ public class StatusBar extends SystemUI implements DemoMode,
boolean fullShadeNeedsBouncer = !mLockscreenUserManager.
userAllowsPrivateNotificationsInPublic(mLockscreenUserManager.getCurrentUserId())
|| !mLockscreenUserManager.shouldShowLockscreenNotifications()
- || mFalsingManager.shouldEnforceBouncer();
+ || mFalsingCollector.shouldEnforceBouncer();
if (mKeyguardBypassController.getBypassEnabled()) {
fullShadeNeedsBouncer = false;
}
@@ -3888,7 +3892,7 @@ public class StatusBar extends SystemUI implements DemoMode,
final ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() {
@Override
public void onScreenTurningOn() {
- mFalsingManager.onScreenTurningOn();
+ mFalsingCollector.onScreenTurningOn();
mNotificationPanelViewController.onScreenTurningOn();
}
@@ -3899,7 +3903,7 @@ public class StatusBar extends SystemUI implements DemoMode,
@Override
public void onScreenTurnedOff() {
- mFalsingManager.onScreenOff();
+ mFalsingCollector.onScreenOff();
mScrimController.onScreenTurnedOff();
updateIsKeyguard();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
index f6631ce1414c..2aa3f37ccf11 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
@@ -31,6 +31,7 @@ import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.InitController;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.UiBackground;
@@ -136,6 +137,7 @@ public interface StatusBarPhoneModule {
DynamicPrivacyController dynamicPrivacyController,
BypassHeadsUpNotifier bypassHeadsUpNotifier,
FalsingManager falsingManager,
+ FalsingCollector falsingCollector,
BroadcastDispatcher broadcastDispatcher,
RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
NotificationGutsManager notificationGutsManager,
@@ -216,6 +218,7 @@ public interface StatusBarPhoneModule {
dynamicPrivacyController,
bypassHeadsUpNotifier,
falsingManager,
+ falsingCollector,
broadcastDispatcher,
remoteInputQuickSettingsDisabler,
notificationGutsManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/ClassifierTest.java
index 69d39fa10b72..472ed7a22fe3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/ClassifierTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
import static com.android.systemui.classifier.Classifier.UNLOCK;
@@ -55,7 +55,7 @@ public class ClassifierTest extends LeakCheckedTest {
resetDataProvider();
}
- FalsingDataProvider getDataProvider() {
+ protected FalsingDataProvider getDataProvider() {
return mDataProvider;
}
@@ -63,15 +63,15 @@ public class ClassifierTest extends LeakCheckedTest {
return mFakeBatteryController;
}
- void setOffsetX(float offsetX) {
+ protected void setOffsetX(float offsetX) {
mOffsetX = offsetX;
}
- void setOffsetY(float offsetY) {
+ protected void setOffsetY(float offsetY) {
mOffsetY = offsetY;
}
- void resetDataProvider() {
+ protected void resetDataProvider() {
for (MotionEvent motionEvent : mMotionEvents) {
motionEvent.recycle();
}
@@ -81,28 +81,28 @@ public class ClassifierTest extends LeakCheckedTest {
mDataProvider.onSessionEnd();
}
- MotionEvent appendDownEvent(float x, float y) {
+ protected MotionEvent appendDownEvent(float x, float y) {
return appendMotionEvent(MotionEvent.ACTION_DOWN, x, y);
}
- MotionEvent appendDownEvent(float x, float y, long eventTime) {
+ protected MotionEvent appendDownEvent(float x, float y, long eventTime) {
return appendMotionEvent(MotionEvent.ACTION_DOWN, x, y, eventTime);
}
- MotionEvent appendMoveEvent(float x, float y) {
+ protected MotionEvent appendMoveEvent(float x, float y) {
return appendMotionEvent(MotionEvent.ACTION_MOVE, x, y);
}
- MotionEvent appendMoveEvent(float x, float y, long eventTime) {
+ protected MotionEvent appendMoveEvent(float x, float y, long eventTime) {
return appendMotionEvent(MotionEvent.ACTION_MOVE, x, y, eventTime);
}
- MotionEvent appendUpEvent(float x, float y) {
+ protected MotionEvent appendUpEvent(float x, float y) {
return appendMotionEvent(MotionEvent.ACTION_UP, x, y);
}
- MotionEvent appendUpEvent(float x, float y, long eventTime) {
+ protected MotionEvent appendUpEvent(float x, float y, long eventTime) {
return appendMotionEvent(MotionEvent.ACTION_UP, x, y, eventTime);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/BrightLineFalsingManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java
index 30dddc02be90..af5e789a0c41 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/BrightLineFalsingManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.never;
@@ -22,123 +22,102 @@ import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.content.res.Resources;
-import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.util.DisplayMetrics;
-import android.view.ViewConfiguration;
-import com.android.internal.logging.testing.UiEventLoggerFake;
+import androidx.test.filters.SmallTest;
+
import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.systemui.R;
-import com.android.systemui.dock.DockManager;
-import com.android.systemui.dock.DockManagerFake;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.StatusBarStateControllerImpl;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
-import com.android.systemui.util.DeviceConfigProxy;
-import com.android.systemui.util.DeviceConfigProxyFake;
import com.android.systemui.util.sensors.ProximitySensor;
import com.android.systemui.util.sensors.ThresholdSensor;
-import com.android.systemui.util.time.FakeSystemClock;
-import com.android.systemui.utils.leaks.FakeBatteryController;
-import com.android.systemui.utils.leaks.LeakCheckedTest;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
-public class BrightLineFalsingManagerTest extends LeakCheckedTest {
-
+public class FalsingCollectorImplTest extends SysuiTestCase {
+ private FalsingCollectorImpl mFalsingCollector;
+ @Mock
+ private FalsingDataProvider mFalsingDataProvider;
+ private final FalsingManagerFake mFalsingManager = new FalsingManagerFake();
@Mock
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock
private ProximitySensor mProximitySensor;
@Mock
- private Resources mResources;
- @Mock
- private ViewConfiguration mViewConfiguration;
private SysuiStatusBarStateController mStatusBarStateController;
- private FalsingDataProvider mFalsingDataProvider;
- private FakeBatteryController mFakeBatteryController;
-
- private BrightLineFalsingManager mFalsingManager;
@Before
- public void setup() {
+ public void setUp() {
MockitoAnnotations.initMocks(this);
- mFakeBatteryController = new FakeBatteryController(getLeakCheck());
- DisplayMetrics dm = new DisplayMetrics();
- dm.xdpi = 100;
- dm.ydpi = 100;
- dm.widthPixels = 100;
- dm.heightPixels = 100;
- mFalsingDataProvider = new FalsingDataProvider(dm, mFakeBatteryController,
- new FakeSystemClock());
- DeviceConfigProxy deviceConfigProxy = new DeviceConfigProxyFake();
- DockManager dockManager = new DockManagerFake();
- mStatusBarStateController = new StatusBarStateControllerImpl(new UiEventLoggerFake());
- mStatusBarStateController.setState(StatusBarState.KEYGUARD);
- when(mResources.getDimension(R.dimen.double_tap_slop)).thenReturn(1f);
- when(mViewConfiguration.getScaledTouchSlop()).thenReturn(1);
- mFalsingManager = new BrightLineFalsingManager(mFalsingDataProvider,
- mKeyguardUpdateMonitor, mProximitySensor, deviceConfigProxy, mResources,
- mViewConfiguration, dockManager, mStatusBarStateController);
+
+ when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
+
+ mFalsingCollector = new FalsingCollectorImpl(mFalsingDataProvider, mFalsingManager,
+ mKeyguardUpdateMonitor, mProximitySensor, mStatusBarStateController);
}
+
@Test
public void testRegisterSensor() {
- mFalsingManager.onScreenTurningOn();
+ mFalsingCollector.onScreenTurningOn();
verify(mProximitySensor).register(any(ThresholdSensor.Listener.class));
}
@Test
public void testNoProximityWhenWirelessCharging() {
- mFakeBatteryController.setWirelessCharging(true);
- mFalsingManager.onScreenTurningOn();
+ when(mFalsingDataProvider.isWirelessCharging()).thenReturn(true);
+ mFalsingCollector.onScreenTurningOn();
verify(mProximitySensor, never()).register(any(ThresholdSensor.Listener.class));
}
@Test
public void testUnregisterSensor() {
- mFalsingManager.onScreenTurningOn();
+ mFalsingCollector.onScreenTurningOn();
reset(mProximitySensor);
- mFalsingManager.onScreenOff();
+ mFalsingCollector.onScreenOff();
verify(mProximitySensor).unregister(any(ThresholdSensor.Listener.class));
}
@Test
public void testUnregisterSensor_QS() {
- mFalsingManager.onScreenTurningOn();
+ mFalsingCollector.onScreenTurningOn();
reset(mProximitySensor);
- mFalsingManager.setQsExpanded(true);
+ mFalsingCollector.setQsExpanded(true);
verify(mProximitySensor).unregister(any(ThresholdSensor.Listener.class));
- mFalsingManager.setQsExpanded(false);
+ mFalsingCollector.setQsExpanded(false);
verify(mProximitySensor).register(any(ThresholdSensor.Listener.class));
}
@Test
public void testUnregisterSensor_Bouncer() {
- mFalsingManager.onScreenTurningOn();
+ mFalsingCollector.onScreenTurningOn();
reset(mProximitySensor);
- mFalsingManager.onBouncerShown();
+ mFalsingCollector.onBouncerShown();
verify(mProximitySensor).unregister(any(ThresholdSensor.Listener.class));
- mFalsingManager.onBouncerHidden();
+ mFalsingCollector.onBouncerHidden();
verify(mProximitySensor).register(any(ThresholdSensor.Listener.class));
}
@Test
public void testUnregisterSensor_StateTransition() {
- mFalsingManager.onScreenTurningOn();
+
+ ArgumentCaptor<StatusBarStateController.StateListener> stateListenerArgumentCaptor =
+ ArgumentCaptor.forClass(StatusBarStateController.StateListener.class);
+ verify(mStatusBarStateController).addCallback(stateListenerArgumentCaptor.capture());
+
+ mFalsingCollector.onScreenTurningOn();
reset(mProximitySensor);
- mStatusBarStateController.setState(StatusBarState.SHADE);
+ stateListenerArgumentCaptor.getValue().onStateChanged(StatusBarState.SHADE);
verify(mProximitySensor).unregister(any(ThresholdSensor.Listener.class));
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/FalsingDataProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java
index be38f4419372..be0cc97a2f0f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/FalsingDataProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.closeTo;
@@ -112,13 +112,6 @@ public class FalsingDataProviderTest extends ClassifierTest {
assertThat(motionEventList.get(1).getX(), is(6f));
assertThat(motionEventList.get(0).getY(), is(7f));
assertThat(motionEventList.get(1).getY(), is(5f));
-
- // The first, real event should still be a, however.
- MotionEvent firstRealMotionEvent = mDataProvider.getFirstActualMotionEvent();
- assertThat(firstRealMotionEvent.getActionMasked(), is(MotionEvent.ACTION_DOWN));
- assertThat(firstRealMotionEvent.getEventTime(), is(1L));
- assertThat(firstRealMotionEvent.getX(), is(2f));
- assertThat(firstRealMotionEvent.getY(), is(9f));
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DiagonalClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DiagonalClassifierTest.java
index e88ff2df60ca..714d6581ff00 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DiagonalClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DiagonalClassifierTest.java
@@ -27,6 +27,8 @@ import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
+import com.android.systemui.classifier.ClassifierTest;
+import com.android.systemui.classifier.FalsingDataProvider;
import com.android.systemui.util.DeviceConfigProxyFake;
import org.junit.After;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DistanceClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DistanceClassifierTest.java
index e5ab9be288ef..d66c7a9d43a5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DistanceClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DistanceClassifierTest.java
@@ -23,6 +23,8 @@ import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
+import com.android.systemui.classifier.ClassifierTest;
+import com.android.systemui.classifier.FalsingDataProvider;
import com.android.systemui.util.DeviceConfigProxyFake;
import org.junit.After;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DoubleTapClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DoubleTapClassifierTest.java
index 9f3a1e4821c9..288ab0ad6596 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DoubleTapClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DoubleTapClassifierTest.java
@@ -27,6 +27,9 @@ import android.view.MotionEvent;
import androidx.test.filters.SmallTest;
+import com.android.systemui.classifier.ClassifierTest;
+import com.android.systemui.classifier.FalsingDataProvider;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/PointerCountClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/PointerCountClassifierTest.java
index 4f8e7c801d04..b512f0d6ef32 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/PointerCountClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/PointerCountClassifierTest.java
@@ -26,6 +26,8 @@ import android.view.MotionEvent;
import androidx.test.filters.SmallTest;
+import com.android.systemui.classifier.ClassifierTest;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ProximityClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ProximityClassifierTest.java
index 3cebf0d6af57..c2e290f166a3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ProximityClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ProximityClassifierTest.java
@@ -28,6 +28,8 @@ import android.view.MotionEvent;
import androidx.test.filters.SmallTest;
+import com.android.systemui.classifier.ClassifierTest;
+import com.android.systemui.classifier.FalsingDataProvider;
import com.android.systemui.util.DeviceConfigProxyFake;
import com.android.systemui.util.sensors.ProximitySensor;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/SingleTapClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/SingleTapClassifierTest.java
index 642b077f0dcf..d67f2b833deb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/SingleTapClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/SingleTapClassifierTest.java
@@ -25,6 +25,9 @@ import android.view.MotionEvent;
import androidx.test.filters.SmallTest;
+import com.android.systemui.classifier.ClassifierTest;
+import com.android.systemui.classifier.FalsingDataProvider;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/TypeClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/TypeClassifierTest.java
index 4346e7df088f..5f3b84c2f7ae 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/TypeClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/TypeClassifierTest.java
@@ -33,6 +33,9 @@ import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
+import com.android.systemui.classifier.ClassifierTest;
+import com.android.systemui.classifier.FalsingDataProvider;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ZigZagClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ZigZagClassifierTest.java
index a8cce00ba996..e49262f5099f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ZigZagClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ZigZagClassifierTest.java
@@ -23,6 +23,7 @@ import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
+import com.android.systemui.classifier.ClassifierTest;
import com.android.systemui.util.DeviceConfigProxyFake;
import org.junit.After;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index f6d6f562e3fa..67d0295c82d3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -41,7 +41,7 @@ import com.android.keyguard.KeyguardDisplayManager;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.classifier.FalsingManagerFake;
+import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -76,18 +76,18 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
private DeviceConfigProxy mDeviceConfig = new DeviceConfigProxyFake();
private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
- private FalsingManagerFake mFalsingManager;
+ private FalsingCollectorFake mFalsingCollector;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mFalsingManager = new FalsingManagerFake();
+ mFalsingCollector = new FalsingCollectorFake();
when(mLockPatternUtils.getDevicePolicyManager()).thenReturn(mDevicePolicyManager);
when(mPowerManager.newWakeLock(anyInt(), any())).thenReturn(mock(WakeLock.class));
mViewMediator = new KeyguardViewMediator(
- mContext, mFalsingManager, mLockPatternUtils, mBroadcastDispatcher,
+ mContext, mFalsingCollector, mLockPatternUtils, mBroadcastDispatcher,
() -> mStatusBarKeyguardViewManager,
mDismissCallbackRegistry, mUpdateMonitor, mDumpManager, mUiBgExecutor,
mPowerManager, mTrustManager, mDeviceConfig, mNavigationModeController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java
index 11ef3e33f9d0..b7cc651dc24b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java
@@ -19,6 +19,8 @@ package com.android.systemui.screenrecord;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
import android.app.PendingIntent;
@@ -128,6 +130,35 @@ public class RecordingControllerTest extends SysuiTestCase {
verify(mCallback).onRecordingEnd();
}
+ // Test that broadcast will update state
+ @Test
+ public void testUpdateStateBroadcast() {
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+
+ // When a recording has started
+ PendingIntent startIntent = Mockito.mock(PendingIntent.class);
+ mController.startCountdown(0, 0, startIntent, null);
+ verify(mCallback).onCountdownEnd();
+
+ // then the receiver was registered
+ verify(mBroadcastDispatcher).registerReceiver(eq(mController.mStateChangeReceiver),
+ any(), any(), any());
+
+ // When the receiver gets an update
+ Intent intent = new Intent(RecordingController.INTENT_UPDATE_STATE);
+ intent.putExtra(RecordingController.EXTRA_STATE, false);
+ mController.mStateChangeReceiver.onReceive(mContext, intent);
+
+ // then the state is updated
+ assertFalse(mController.isRecording());
+ verify(mCallback).onRecordingEnd();
+
+ // and the receiver is unregistered
+ verify(mBroadcastDispatcher).unregisterReceiver(eq(mController.mStateChangeReceiver));
+ }
+
// Test that switching users will stop an ongoing recording
@Test
public void testUserChange() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
index 3e37fde84544..91cafead596c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
@@ -17,15 +17,18 @@
package com.android.systemui.screenrecord;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.app.Notification;
import android.app.NotificationManager;
import android.content.Intent;
+import android.os.RemoteException;
import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
@@ -43,6 +46,7 @@ import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
+import java.io.IOException;
import java.util.concurrent.Executor;
@RunWith(AndroidTestingRunner.class)
@@ -88,6 +92,9 @@ public class RecordingServiceTest extends SysuiTestCase {
doNothing().when(mRecordingService).createRecordingNotification();
doReturn(mNotification).when(mRecordingService).createProcessingNotification();
doReturn(mNotification).when(mRecordingService).createSaveNotification(any());
+ doNothing().when(mRecordingService).createErrorNotification();
+ doNothing().when(mRecordingService).showErrorToast(anyInt());
+ doNothing().when(mRecordingService).stopForeground(anyBoolean());
doNothing().when(mRecordingService).startForeground(anyInt(), any());
doReturn(mScreenMediaRecorder).when(mRecordingService).getRecorder();
@@ -124,4 +131,16 @@ public class RecordingServiceTest extends SysuiTestCase {
.log(Events.ScreenRecordEvent.SCREEN_RECORD_END_NOTIFICATION);
verify(mUiEventLogger, times(0)).log(Events.ScreenRecordEvent.SCREEN_RECORD_END_QS_TILE);
}
+
+ @Test
+ public void testErrorUpdatesState() throws IOException, RemoteException {
+ // When the screen recording does not start properly
+ doThrow(new RuntimeException("fail")).when(mScreenMediaRecorder).start();
+
+ Intent startIntent = RecordingService.getStartIntent(mContext, 0, 0, false);
+ mRecordingService.onStartCommand(startIntent, 0, 0);
+
+ // Then the state is set to not recording
+ verify(mController).updateState(false);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
index dbaf5c467c45..ababebdd807c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
@@ -44,9 +44,9 @@ import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.NotificationMessagingUtil;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.media.MediaFeatureFlag;
import com.android.systemui.media.dialog.MediaOutputDialogFactory;
-import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.FeatureFlags;
@@ -129,7 +129,6 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase {
@Mock(answer = Answers.RETURNS_SELF)
private ExpandableNotificationRowComponent.Builder mExpandableNotificationRowComponentBuilder;
@Mock private ExpandableNotificationRowComponent mExpandableNotificationRowComponent;
- @Mock private FalsingManager mFalsingManager;
@Mock private KeyguardBypassController mKeyguardBypassController;
@Mock private StatusBarStateController mStatusBarStateController;
@@ -244,7 +243,7 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase {
mGutsManager,
true,
null,
- mFalsingManager,
+ new FalsingCollectorFake(),
mPeopleNotificationIdentifier,
Optional.of(mock(BubblesManager.class))
));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index baae8fda18f9..7470a13ae39e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -45,9 +45,9 @@ import android.widget.RemoteViews;
import com.android.systemui.R;
import com.android.systemui.TestableDependency;
+import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.media.MediaFeatureFlag;
import com.android.systemui.media.dialog.MediaOutputDialogFactory;
-import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
@@ -428,7 +428,7 @@ public class NotificationTestHelper {
mock(OnExpandClickListener.class),
mock(NotificationMediaManager.class),
mock(ExpandableNotificationRow.CoordinateOnClickListener.class),
- mock(FalsingManager.class),
+ new FalsingCollectorFake(),
mStatusBarStateController,
mPeopleNotificationIdentifier,
mock(OnUserInteractionCallback.class),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java
index 01d49c269fb2..3c4fde8f6106 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java
@@ -42,9 +42,9 @@ import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.media.KeyguardMediaController;
-import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -106,7 +106,6 @@ public class NotificationStackScrollerControllerTest extends SysuiTestCase {
@Mock private SysuiColorExtractor mColorExtractor;
@Mock private NotificationLockscreenUserManager mNotificationLockscreenUserManager;
@Mock private MetricsLogger mMetricsLogger;
- @Mock private FalsingManager mFalsingManager;
@Mock private Resources mResources;
@Mock(answer = Answers.RETURNS_SELF)
private NotificationSwipeHelper.Builder mNotificationSwipeHelperBuilder;
@@ -160,7 +159,7 @@ public class NotificationStackScrollerControllerTest extends SysuiTestCase {
mColorExtractor,
mNotificationLockscreenUserManager,
mMetricsLogger,
- mFalsingManager,
+ new FalsingCollectorFake(),
mResources,
mNotificationSwipeHelperBuilder,
mStatusBar,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
index 1b05ad7f8b5b..bc014ec16103 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
@@ -50,9 +50,9 @@ import com.android.keyguard.ViewMediatorCallback;
import com.android.keyguard.dagger.KeyguardBouncerComponent;
import com.android.systemui.DejankUtils;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
-import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import org.junit.Assert;
@@ -72,7 +72,7 @@ import org.mockito.stubbing.Answer;
public class KeyguardBouncerTest extends SysuiTestCase {
@Mock
- private FalsingManager mFalsingManager;
+ private FalsingCollector mFalsingCollector;
@Mock
private ViewMediatorCallback mViewMediatorCallback;
@Mock
@@ -128,7 +128,7 @@ public class KeyguardBouncerTest extends SysuiTestCase {
final ViewGroup container = new FrameLayout(getContext());
mBouncer = new KeyguardBouncer.Factory(getContext(), mViewMediatorCallback,
- mDismissCallbackRegistry, mFalsingManager,
+ mDismissCallbackRegistry, mFalsingCollector,
mKeyguardStateController, mKeyguardUpdateMonitor,
mKeyguardBypassController, mHandler, mKeyguardSecurityModel,
mKeyguardBouncerComponentFactory)
@@ -143,10 +143,10 @@ public class KeyguardBouncerTest extends SysuiTestCase {
@Test
public void testShow_notifiesFalsingManager() {
mBouncer.show(true);
- verify(mFalsingManager).onBouncerShown();
+ verify(mFalsingCollector).onBouncerShown();
mBouncer.show(true, false);
- verifyNoMoreInteractions(mFalsingManager);
+ verifyNoMoreInteractions(mFalsingCollector);
}
/**
@@ -212,11 +212,11 @@ public class KeyguardBouncerTest extends SysuiTestCase {
mBouncer.setExpansion(0.5f);
mBouncer.setExpansion(KeyguardBouncer.EXPANSION_HIDDEN);
- verify(mFalsingManager).onBouncerHidden();
+ verify(mFalsingCollector).onBouncerHidden();
verify(mExpansionCallback).onFullyHidden();
mBouncer.setExpansion(KeyguardBouncer.EXPANSION_VISIBLE);
- verify(mFalsingManager).onBouncerShown();
+ verify(mFalsingCollector).onBouncerShown();
verify(mExpansionCallback).onFullyShown();
verify(mExpansionCallback, never()).onStartingToHide();
@@ -239,7 +239,7 @@ public class KeyguardBouncerTest extends SysuiTestCase {
@Test
public void testHide_notifiesFalsingManager() {
mBouncer.hide(false);
- verify(mFalsingManager).onBouncerHidden();
+ verify(mFalsingCollector).onBouncerHidden();
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index 4841b3bf951f..3d582e74ea4e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -60,10 +60,10 @@ import com.android.keyguard.dagger.KeyguardStatusViewComponent;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.biometrics.AuthController;
+import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.media.MediaHierarchyManager;
-import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.qs.QSDetailDisplayer;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.KeyguardAffordanceView;
@@ -132,8 +132,6 @@ public class NotificationPanelViewTest extends SysuiTestCase {
@Mock
private KeyguardUpdateMonitor mUpdateMonitor;
@Mock
- private FalsingManager mFalsingManager;
- @Mock
private KeyguardBypassController mKeyguardBypassController;
@Mock
private DozeParameters mDozeParameters;
@@ -252,7 +250,7 @@ public class NotificationPanelViewTest extends SysuiTestCase {
mKeyguardBypassController, mHeadsUpManager,
mock(NotificationRoundnessManager.class),
mStatusBarStateController,
- new FalsingManagerFake());
+ new FalsingManagerFake(), new FalsingCollectorFake());
when(mKeyguardStatusViewComponentFactory.build(any()))
.thenReturn(mKeyguardStatusViewComponent);
when(mKeyguardStatusViewComponent.getKeyguardClockSwitchController())
@@ -263,7 +261,7 @@ public class NotificationPanelViewTest extends SysuiTestCase {
mResources,
mInjectionInflationController,
coordinator, expansionHandler, mDynamicPrivacyController, mKeyguardBypassController,
- mFalsingManager, mShadeController,
+ new FalsingManagerFake(), new FalsingCollectorFake(), mShadeController,
mNotificationLockscreenUserManager, mNotificationEntryManager,
mKeyguardStateController, mStatusBarStateController, mDozeLog,
mDozeParameters, mCommandQueue, mVibratorHelper,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
index 25af584ed3f8..e0fa9babbb48 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
@@ -30,6 +30,7 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.R;
import com.android.systemui.SystemUIFactory;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.dock.DockManager;
import com.android.systemui.doze.DozeLog;
@@ -111,6 +112,7 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase {
mDynamicPrivacyController,
mBypassController,
new FalsingManagerFake(),
+ new FalsingCollectorFake(),
mPluginManager,
mTunerService,
mNotificationLockScreenUserManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 710122d83b22..5416f75dffff 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -83,6 +83,7 @@ import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.demomode.DemoModeController;
@@ -356,6 +357,7 @@ public class StatusBarTest extends SysuiTestCase {
mDynamicPrivacyController,
mBypassHeadsUpNotifier,
new FalsingManagerFake(),
+ new FalsingCollectorFake(),
mBroadcastDispatcher,
new RemoteInputQuickSettingsDisabler(
mContext,
diff --git a/packages/services/PacProcessor/AndroidManifest.xml b/packages/services/PacProcessor/AndroidManifest.xml
index ad1326194a4d..533098cbdc75 100644
--- a/packages/services/PacProcessor/AndroidManifest.xml
+++ b/packages/services/PacProcessor/AndroidManifest.xml
@@ -3,6 +3,7 @@
package="com.android.pacprocessor">
<uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:label="@string/app_name"
diff --git a/services/companion/java/com/android/server/companion/OWNERS b/services/companion/java/com/android/server/companion/OWNERS
new file mode 100644
index 000000000000..da723b3b67da
--- /dev/null
+++ b/services/companion/java/com/android/server/companion/OWNERS
@@ -0,0 +1 @@
+eugenesusla@google.com \ No newline at end of file
diff --git a/services/core/java/android/app/usage/UsageStatsManagerInternal.java b/services/core/java/android/app/usage/UsageStatsManagerInternal.java
index fa84427ac064..b2226d1e0fa3 100644
--- a/services/core/java/android/app/usage/UsageStatsManagerInternal.java
+++ b/services/core/java/android/app/usage/UsageStatsManagerInternal.java
@@ -326,4 +326,18 @@ public abstract class UsageStatsManagerInternal {
* @return {@code true} if the updating was successful, {@code false} otherwise
*/
public abstract boolean updatePackageMappingsData();
+
+ /**
+ * Listener interface for usage events.
+ */
+ public interface UsageEventListener {
+ /** Callback to inform listeners of a new usage event. */
+ void onUsageEvent(@UserIdInt int userId, @NonNull UsageEvents.Event event);
+ }
+
+ /** Register a listener that will be notified of every new usage event. */
+ public abstract void registerListener(@NonNull UsageEventListener listener);
+
+ /** Unregister a listener from being notified of every new usage event. */
+ public abstract void unregisterListener(@NonNull UsageEventListener listener);
}
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index f20566280bc8..6989e320f465 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -77,6 +77,7 @@ public abstract class PackageManagerInternal {
PACKAGE_WIFI,
PACKAGE_COMPANION,
PACKAGE_RETAIL_DEMO,
+ PACKAGE_RECENTS,
})
@Retention(RetentionPolicy.SOURCE)
public @interface KnownPackage {}
@@ -97,9 +98,10 @@ public abstract class PackageManagerInternal {
public static final int PACKAGE_WIFI = 13;
public static final int PACKAGE_COMPANION = 14;
public static final int PACKAGE_RETAIL_DEMO = 15;
+ public static final int PACKAGE_RECENTS = 16;
// Integer value of the last known package ID. Increases as new ID is added to KnownPackage.
// Please note the numbers should be continuous.
- public static final int LAST_KNOWN_PACKAGE = PACKAGE_RETAIL_DEMO;
+ public static final int LAST_KNOWN_PACKAGE = PACKAGE_RECENTS;
@IntDef(flag = true, prefix = "RESOLVE_", value = {
RESOLVE_NON_BROWSER_ONLY,
@@ -1060,6 +1062,8 @@ public abstract class PackageManagerInternal {
return "Retail Demo";
case PACKAGE_OVERLAY_CONFIG_SIGNATURE:
return "Overlay Config Signature";
+ case PACKAGE_RECENTS:
+ return "Recents";
}
return "Unknown";
}
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
index 735d248b12e4..f3c5fd8d1064 100644
--- a/services/core/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -47,7 +47,6 @@ import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BackgroundThread;
-import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.XmlUtils;
@@ -64,7 +63,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
@@ -129,9 +127,17 @@ public class PackageWatchdog {
@VisibleForTesting
static final int DEFAULT_BOOT_LOOP_TRIGGER_COUNT = 5;
static final long DEFAULT_BOOT_LOOP_TRIGGER_WINDOW_MS = TimeUnit.MINUTES.toMillis(10);
+
+ // These properties track individual system server boot events, and are reset once the boot
+ // threshold is met, or the boot loop trigger window is exceeded between boot events.
private static final String PROP_RESCUE_BOOT_COUNT = "sys.rescue_boot_count";
private static final String PROP_RESCUE_BOOT_START = "sys.rescue_boot_start";
+ // These properties track multiple calls made to observers tracking boot loops. They are reset
+ // when the de-escalation window is exceeded between boot events.
+ private static final String PROP_BOOT_MITIGATION_WINDOW_START = "sys.boot_mitigation_start";
+ private static final String PROP_BOOT_MITIGATION_COUNT = "sys.boot_mitigation_count";
+
private long mNumberOfNativeCrashPollsRemaining;
private static final int DB_VERSION = 1;
@@ -191,7 +197,6 @@ public class PackageWatchdog {
@FunctionalInterface
@VisibleForTesting
interface SystemClock {
- // TODO: Add elapsedRealtime to this interface
long uptimeMillis();
}
@@ -471,13 +476,14 @@ public class PackageWatchdog {
synchronized (mLock) {
if (mBootThreshold.incrementAndTest()) {
mBootThreshold.reset();
+ int mitigationCount = mBootThreshold.getMitigationCount() + 1;
PackageHealthObserver currentObserverToNotify = null;
int currentObserverImpact = Integer.MAX_VALUE;
for (int i = 0; i < mAllObservers.size(); i++) {
final ObserverInternal observer = mAllObservers.valueAt(i);
PackageHealthObserver registeredObserver = observer.registeredObserver;
if (registeredObserver != null) {
- int impact = registeredObserver.onBootLoop();
+ int impact = registeredObserver.onBootLoop(mitigationCount);
if (impact != PackageHealthObserverImpact.USER_IMPACT_NONE
&& impact < currentObserverImpact) {
currentObserverToNotify = registeredObserver;
@@ -486,7 +492,8 @@ public class PackageWatchdog {
}
}
if (currentObserverToNotify != null) {
- currentObserverToNotify.executeBootLoopMitigation();
+ mBootThreshold.setMitigationCount(mitigationCount);
+ currentObserverToNotify.executeBootLoopMitigation(mitigationCount);
}
}
}
@@ -609,15 +616,20 @@ public class PackageWatchdog {
/**
* Called when the system server has booted several times within a window of time, defined
* by {@link #mBootThreshold}
+ *
+ * @param mitigationCount the number of times mitigation has been attempted for this
+ * boot loop (including this time).
*/
- default @PackageHealthObserverImpact int onBootLoop() {
+ default @PackageHealthObserverImpact int onBootLoop(int mitigationCount) {
return PackageHealthObserverImpact.USER_IMPACT_NONE;
}
/**
* Executes mitigation for {@link #onBootLoop}
+ * @param mitigationCount the number of times mitigation has been attempted for this
+ * boot loop (including this time).
*/
- default boolean executeBootLoopMitigation() {
+ default boolean executeBootLoopMitigation(int mitigationCount) {
return false;
}
@@ -1577,7 +1589,7 @@ public class PackageWatchdog {
/**
* Handles the thresholding logic for system server boots.
*/
- static class BootThreshold {
+ class BootThreshold {
private final int mBootTriggerCount;
private final long mTriggerWindow;
@@ -1604,18 +1616,44 @@ public class PackageWatchdog {
return SystemProperties.getLong(PROP_RESCUE_BOOT_START, 0);
}
+ public int getMitigationCount() {
+ return SystemProperties.getInt(PROP_BOOT_MITIGATION_COUNT, 0);
+ }
+
public void setStart(long start) {
- final long now = android.os.SystemClock.elapsedRealtime();
+ setPropertyStart(PROP_RESCUE_BOOT_START, start);
+ }
+
+ public void setMitigationStart(long start) {
+ setPropertyStart(PROP_BOOT_MITIGATION_WINDOW_START, start);
+ }
+
+ public long getMitigationStart() {
+ return SystemProperties.getLong(PROP_BOOT_MITIGATION_WINDOW_START, 0);
+ }
+
+ public void setMitigationCount(int count) {
+ SystemProperties.set(PROP_BOOT_MITIGATION_COUNT, Integer.toString(count));
+ }
+
+ public void setPropertyStart(String property, long start) {
+ final long now = mSystemClock.uptimeMillis();
final long newStart = MathUtils.constrain(start, 0, now);
- SystemProperties.set(PROP_RESCUE_BOOT_START, Long.toString(newStart));
+ SystemProperties.set(property, Long.toString(newStart));
}
+
/** Increments the boot counter, and returns whether the device is bootlooping. */
public boolean incrementAndTest() {
- final long now = android.os.SystemClock.elapsedRealtime();
+ final long now = mSystemClock.uptimeMillis();
if (now - getStart() < 0) {
Slog.e(TAG, "Window was less than zero. Resetting start to current time.");
setStart(now);
+ setMitigationStart(now);
+ }
+ if (now - getMitigationStart() > DEFAULT_DEESCALATION_WINDOW_MS) {
+ setMitigationCount(0);
+ setMitigationStart(now);
}
final long window = now - getStart();
if (window >= mTriggerWindow) {
diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java
index d04949ac54db..e8e1a16d116b 100644
--- a/services/core/java/com/android/server/RescueParty.java
+++ b/services/core/java/com/android/server/RescueParty.java
@@ -29,7 +29,6 @@ import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.FileUtils;
-import android.os.Process;
import android.os.RecoverySystem;
import android.os.RemoteCallback;
import android.os.SystemClock;
@@ -40,7 +39,6 @@ import android.provider.Settings;
import android.util.ArraySet;
import android.util.ExceptionUtils;
import android.util.Log;
-import android.util.MathUtils;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
@@ -75,8 +73,6 @@ import java.util.concurrent.TimeUnit;
public class RescueParty {
@VisibleForTesting
static final String PROP_ENABLE_RESCUE = "persist.sys.enable_rescue";
- @VisibleForTesting
- static final String PROP_RESCUE_LEVEL = "sys.rescue_level";
static final String PROP_ATTEMPTING_FACTORY_RESET = "sys.attempting_factory_reset";
static final String PROP_MAX_RESCUE_LEVEL_ATTEMPTED = "sys.max_rescue_level_attempted";
@VisibleForTesting
@@ -168,7 +164,6 @@ public class RescueParty {
*/
public static void onSettingsProviderPublished(Context context) {
handleNativeRescuePartyResets();
- executeRescueLevel(context, /*failedPackage=*/ null);
ContentResolver contentResolver = context.getContentResolver();
Settings.Config.registerMonitorCallback(contentResolver, new RemoteCallback(result -> {
handleMonitorCallback(context, result);
@@ -260,33 +255,6 @@ public class RescueParty {
}
}
- /**
- * Get the next rescue level. This indicates the next level of mitigation that may be taken.
- */
- private static int getNextRescueLevel() {
- return MathUtils.constrain(SystemProperties.getInt(PROP_RESCUE_LEVEL, LEVEL_NONE) + 1,
- LEVEL_NONE, getMaxRescueLevel());
- }
-
- /**
- * Escalate to the next rescue level. After incrementing the level you'll
- * probably want to call {@link #executeRescueLevel(Context, String)}.
- */
- private static void incrementRescueLevel(int triggerUid) {
- final int level = getNextRescueLevel();
- SystemProperties.set(PROP_RESCUE_LEVEL, Integer.toString(level));
-
- EventLogTags.writeRescueLevel(level, triggerUid);
- logCriticalInfo(Log.WARN, "Incremented rescue level to "
- + levelToString(level) + " triggered by UID " + triggerUid);
- }
-
- private static void executeRescueLevel(Context context, @Nullable String failedPackage) {
- final int level = SystemProperties.getInt(PROP_RESCUE_LEVEL, LEVEL_NONE);
- if (level == LEVEL_NONE) return;
- executeRescueLevel(context, failedPackage, level);
- }
-
private static void executeRescueLevel(Context context, @Nullable String failedPackage,
int level) {
Slog.w(TAG, "Attempting rescue level " + levelToString(level));
@@ -561,20 +529,19 @@ public class RescueParty {
}
@Override
- public int onBootLoop() {
+ public int onBootLoop(int mitigationCount) {
if (isDisabled()) {
return PackageHealthObserverImpact.USER_IMPACT_NONE;
}
- return mapRescueLevelToUserImpact(getNextRescueLevel());
+ return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount));
}
@Override
- public boolean executeBootLoopMitigation() {
+ public boolean executeBootLoopMitigation(int mitigationCount) {
if (isDisabled()) {
return false;
}
- incrementRescueLevel(Process.ROOT_UID);
- executeRescueLevel(mContext, /*failedPackage=*/ null);
+ executeRescueLevel(mContext, /*failedPackage=*/ null, getRescueLevel(mitigationCount));
return true;
}
diff --git a/services/core/java/com/android/server/am/ActiveInstrumentation.java b/services/core/java/com/android/server/am/ActiveInstrumentation.java
index 43474d5f22d4..61ccf11ff73e 100644
--- a/services/core/java/com/android/server/am/ActiveInstrumentation.java
+++ b/services/core/java/com/android/server/am/ActiveInstrumentation.java
@@ -52,6 +52,9 @@ class ActiveInstrumentation {
// Whether the caller holds START_ACTIVITIES_FROM_BACKGROUND permission
boolean mHasBackgroundActivityStartsPermission;
+ // Whether the caller holds START_FOREGROUND_SERVICES_FROM_BACKGROUND permission
+ boolean mHasBackgroundForegroundServiceStartsPermission;
+
// As given to us
Bundle mArguments;
@@ -128,6 +131,8 @@ class ActiveInstrumentation {
}
pw.print("mHasBackgroundActivityStartsPermission=");
pw.println(mHasBackgroundActivityStartsPermission);
+ pw.print("mHasBackgroundForegroundServiceStartsPermission=");
+ pw.println(mHasBackgroundForegroundServiceStartsPermission);
pw.print(prefix); pw.print("mArguments=");
pw.println(mArguments);
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index d6f72990e4ac..872902626fb4 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -17,6 +17,8 @@
package com.android.server.am;
import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
+import static android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND;
+import static android.Manifest.permission.SYSTEM_ALERT_WINDOW;
import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST;
@@ -56,9 +58,11 @@ import android.app.PendingIntent;
import android.app.Service;
import android.app.ServiceStartArgs;
import android.app.admin.DevicePolicyEventLogger;
+import android.app.compat.CompatChanges;
import android.appwidget.AppWidgetManagerInternal;
import android.compat.annotation.ChangeId;
import android.compat.annotation.Disabled;
+import android.compat.annotation.EnabledSince;
import android.content.ComponentName;
import android.content.ComponentName.WithComponentName;
import android.content.Context;
@@ -104,7 +108,6 @@ import android.webkit.WebViewZygote;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.procstats.ServiceState;
-import com.android.internal.compat.IPlatformCompat;
import com.android.internal.messages.nano.SystemMessageProto;
import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.BatteryStatsImpl;
@@ -147,30 +150,40 @@ public final class ActiveServices {
public static final int FGS_FEATURE_DENIED = 0;
public static final int FGS_FEATURE_ALLOWED_BY_UID_STATE = 1;
- public static final int FGS_FEATURE_ALLOWED_BY_UID_VISIBLE = 2;
- public static final int FGS_FEATURE_ALLOWED_BY_FLAG = 3;
- public static final int FGS_FEATURE_ALLOWED_BY_SYSTEM_UID = 4;
- public static final int FGS_FEATURE_ALLOWED_BY_INSTR_PERMISSION = 5;
- public static final int FGS_FEATURE_ALLOWED_BY_TOKEN = 6;
- public static final int FGS_FEATURE_ALLOWED_BY_PERMISSION = 7;
- public static final int FGS_FEATURE_ALLOWED_BY_WHITELIST = 8;
- public static final int FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER = 9;
- public static final int FGS_FEATURE_ALLOWED_BY_PROC_STATE = 10;
- public static final int FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST = 11;
+ public static final int FGS_FEATURE_ALLOWED_BY_PROC_STATE = 2;
+ public static final int FGS_FEATURE_ALLOWED_BY_UID_VISIBLE = 3;
+ public static final int FGS_FEATURE_ALLOWED_BY_FLAG = 4;
+ public static final int FGS_FEATURE_ALLOWED_BY_SYSTEM_UID = 5;
+ public static final int FGS_FEATURE_ALLOWED_BY_INSTR_BACKGROUND_ACTIVITY_PERMISSION = 6;
+ public static final int FGS_FEATURE_ALLOWED_BY_INSTR_BACKGROUND_FGS_PERMISSION = 7;
+ public static final int FGS_FEATURE_ALLOWED_BY_ACTIVITY_TOKEN = 8;
+ public static final int FGS_FEATURE_ALLOWED_BY_FGS_TOKEN = 9;
+ public static final int FGS_FEATURE_ALLOWED_BY_BACKGROUND_ACTIVITY_PERMISSION = 10;
+ public static final int FGS_FEATURE_ALLOWED_BY_BACKGROUND_FGS_PERMISSION = 12;
+ public static final int FGS_FEATURE_ALLOWED_BY_ALLOWLIST = 13;
+ public static final int FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER = 14;
+ public static final int FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST = 15;
+ public static final int FGS_FEATURE_ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION = 16;
+ public static final int FGS_FEATURE_ALLOWED_BY_FGS_BINDING = 17;
@IntDef(flag = true, prefix = { "FGS_FEATURE_" }, value = {
FGS_FEATURE_DENIED,
FGS_FEATURE_ALLOWED_BY_UID_STATE,
+ FGS_FEATURE_ALLOWED_BY_PROC_STATE,
FGS_FEATURE_ALLOWED_BY_UID_VISIBLE,
FGS_FEATURE_ALLOWED_BY_FLAG,
FGS_FEATURE_ALLOWED_BY_SYSTEM_UID,
- FGS_FEATURE_ALLOWED_BY_INSTR_PERMISSION,
- FGS_FEATURE_ALLOWED_BY_TOKEN,
- FGS_FEATURE_ALLOWED_BY_PERMISSION,
- FGS_FEATURE_ALLOWED_BY_WHITELIST,
+ FGS_FEATURE_ALLOWED_BY_INSTR_BACKGROUND_ACTIVITY_PERMISSION,
+ FGS_FEATURE_ALLOWED_BY_INSTR_BACKGROUND_FGS_PERMISSION,
+ FGS_FEATURE_ALLOWED_BY_ACTIVITY_TOKEN,
+ FGS_FEATURE_ALLOWED_BY_FGS_TOKEN,
+ FGS_FEATURE_ALLOWED_BY_BACKGROUND_ACTIVITY_PERMISSION,
+ FGS_FEATURE_ALLOWED_BY_BACKGROUND_FGS_PERMISSION,
+ FGS_FEATURE_ALLOWED_BY_ALLOWLIST,
FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER,
- FGS_FEATURE_ALLOWED_BY_PROC_STATE,
- FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST
+ FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST,
+ FGS_FEATURE_ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION,
+ FGS_FEATURE_ALLOWED_BY_FGS_BINDING
})
@Retention(RetentionPolicy.SOURCE)
public @interface FgsFeatureRetCode {}
@@ -242,14 +255,12 @@ public final class ActiveServices {
AppWidgetManagerInternal mAppWidgetManagerInternal;
// white listed packageName.
- ArraySet<String> mWhiteListAllowWhileInUsePermissionInFgs = new ArraySet<>();
+ ArraySet<String> mAllowListWhileInUsePermissionInFgs = new ArraySet<>();
// TODO: remove this after feature development is done
private static final SimpleDateFormat DATE_FORMATTER =
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- private final IPlatformCompat mPlatformCompat;
-
/**
* The BG-launch FGS restriction feature is going to be allowed only for apps targetSdkVersion
* is higher than R.
@@ -258,6 +269,14 @@ public final class ActiveServices {
@Disabled
static final long FGS_BG_START_RESTRICTION_CHANGE_ID = 170668199L;
+ /**
+ * If a service can not become foreground service due to BG-FGS-launch restriction or other
+ * reasons, throws an IllegalStateException.
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.S)
+ static final long FGS_START_EXCEPTION_CHANGE_ID = 174041399L;
+
final Runnable mLastAnrDumpClearer = new Runnable() {
@Override public void run() {
synchronized (mAm) {
@@ -456,26 +475,25 @@ public final class ActiveServices {
? maxBg : ActivityManager.isLowRamDeviceStatic() ? 1 : 8;
final IBinder b = ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE);
- mPlatformCompat = IPlatformCompat.Stub.asInterface(b);
}
void systemServicesReady() {
AppStateTracker ast = LocalServices.getService(AppStateTracker.class);
ast.addServiceStateListener(new ForcedStandbyListener());
mAppWidgetManagerInternal = LocalServices.getService(AppWidgetManagerInternal.class);
- setWhiteListAllowWhileInUsePermissionInFgs();
+ setAllowListWhileInUsePermissionInFgs();
}
- private void setWhiteListAllowWhileInUsePermissionInFgs() {
+ private void setAllowListWhileInUsePermissionInFgs() {
final String attentionServicePackageName =
mAm.mContext.getPackageManager().getAttentionServicePackageName();
if (!TextUtils.isEmpty(attentionServicePackageName)) {
- mWhiteListAllowWhileInUsePermissionInFgs.add(attentionServicePackageName);
+ mAllowListWhileInUsePermissionInFgs.add(attentionServicePackageName);
}
final String systemCaptionsServicePackageName =
mAm.mContext.getPackageManager().getSystemCaptionsServicePackageName();
if (!TextUtils.isEmpty(systemCaptionsServicePackageName)) {
- mWhiteListAllowWhileInUsePermissionInFgs.add(systemCaptionsServicePackageName);
+ mAllowListWhileInUsePermissionInFgs.add(systemCaptionsServicePackageName);
}
}
@@ -583,13 +601,27 @@ public final class ActiveServices {
Slog.wtf(TAG, "Background started FGS " + r.mInfoAllowStartForeground);
r.mLoggedInfoAllowStartForeground = true;
}
- if (r.mAllowStartForeground == FGS_FEATURE_DENIED
- && (mAm.mConstants.mFlagFgsStartRestrictionEnabled
- || isChangeEnabled(FGS_BG_START_RESTRICTION_CHANGE_ID, r))) {
- Slog.w(TAG, "startForegroundService() not allowed due to "
+ if (r.mAllowStartForeground == FGS_FEATURE_DENIED && isBgFgsRestrictionEnabled(r)) {
+ String msg = "startForegroundService() not allowed due to "
+ "mAllowStartForeground false: service "
- + r.shortInstanceName);
+ + r.shortInstanceName;
+ Slog.w(TAG, msg);
showFgsBgRestrictedNotificationLocked(r);
+ ApplicationInfo aInfo = null;
+ try {
+ aInfo = AppGlobals.getPackageManager().getApplicationInfo(
+ callingPackage, ActivityManagerService.STOCK_PM_FLAGS,
+ userId);
+ } catch (android.os.RemoteException e) {
+ // pm is in same process, this will never happen.
+ }
+ if (aInfo == null) {
+ throw new SecurityException("startServiceLocked failed, "
+ + "could not resolve client package " + callingPackage);
+ }
+ if (CompatChanges.isChangeEnabled(FGS_START_EXCEPTION_CHANGE_ID, aInfo.uid)) {
+ throw new IllegalStateException(msg);
+ }
return null;
}
}
@@ -1449,7 +1481,7 @@ public final class ActiveServices {
}
try {
- boolean ignoreForeground = false;
+ String ignoreForeground = null;
final int mode = mAm.getAppOpsManager().checkOpNoThrow(
AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName);
switch (mode) {
@@ -1459,9 +1491,9 @@ public final class ActiveServices {
break;
case AppOpsManager.MODE_IGNORED:
// Whoops, silently ignore this.
- Slog.w(TAG, "Service.startForeground() not allowed due to app op: service "
- + r.shortInstanceName);
- ignoreForeground = true;
+ ignoreForeground = "Service.startForeground() not allowed due to app op: "
+ + "service " + r.shortInstanceName;
+ Slog.w(TAG, ignoreForeground);
break;
default:
throw new SecurityException("Foreground not allowed as per app op");
@@ -1469,19 +1501,18 @@ public final class ActiveServices {
// Apps that are TOP or effectively similar may call startForeground() on
// their services even if they are restricted from doing that while in bg.
- if (!ignoreForeground
+ if (ignoreForeground == null
&& !appIsTopLocked(r.appInfo.uid)
&& appRestrictedAnyInBackground(r.appInfo.uid, r.packageName)) {
- Slog.w(TAG,
- "Service.startForeground() not allowed due to bg restriction: service "
- + r.shortInstanceName);
+ ignoreForeground = "Service.startForeground() not allowed due to bg restriction"
+ + ":service " + r.shortInstanceName;
+ Slog.w(TAG, ignoreForeground);
// Back off of any foreground expectations around this service, since we've
// just turned down its fg request.
updateServiceForegroundLocked(r.app, false);
- ignoreForeground = true;
}
- if (!ignoreForeground) {
+ if (ignoreForeground == null) {
if (isFgsBgStart(r.mAllowStartForeground)) {
if (!r.mLoggedInfoAllowStartForeground) {
Slog.wtf(TAG, "Background started FGS "
@@ -1489,14 +1520,13 @@ public final class ActiveServices {
r.mLoggedInfoAllowStartForeground = true;
}
if (r.mAllowStartForeground == FGS_FEATURE_DENIED
- && (mAm.mConstants.mFlagFgsStartRestrictionEnabled
- || isChangeEnabled(FGS_BG_START_RESTRICTION_CHANGE_ID, r))) {
- Slog.w(TAG, "Service.startForeground() not allowed due to "
- + "mAllowStartForeground false: service "
- + r.shortInstanceName);
+ && isBgFgsRestrictionEnabled(r)) {
+ ignoreForeground = "Service.startForeground() not allowed due to "
+ + "mAllowStartForeground false: service "
+ + r.shortInstanceName;
+ Slog.w(TAG, ignoreForeground);
showFgsBgRestrictedNotificationLocked(r);
updateServiceForegroundLocked(r.app, true);
- ignoreForeground = true;
}
}
}
@@ -1505,7 +1535,7 @@ public final class ActiveServices {
// services, so now that we've enforced the startForegroundService() contract
// we only do the machinery of making the service foreground when the app
// is not restricted.
- if (!ignoreForeground) {
+ if (ignoreForeground == null) {
if (r.foregroundId != id) {
cancelForegroundNotificationLocked(r);
r.foregroundId = id;
@@ -1567,6 +1597,10 @@ public final class ActiveServices {
if (DEBUG_FOREGROUND_SERVICE) {
Slog.d(TAG, "Suppressing startForeground() for FAS " + r);
}
+ if (CompatChanges.isChangeEnabled(FGS_START_EXCEPTION_CHANGE_ID, r.appInfo.uid)
+ && isBgFgsRestrictionEnabled(r)) {
+ throw new IllegalStateException(ignoreForeground);
+ }
}
} finally {
if (stopProcStatsOp) {
@@ -2094,6 +2128,12 @@ public final class ActiveServices {
"BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS");
}
+ if ((flags & Context.BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND) != 0) {
+ mAm.enforceCallingPermission(
+ android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND,
+ "BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND");
+ }
+
final boolean callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
final boolean isBindExternal = (flags & Context.BIND_EXTERNAL_SERVICE) != 0;
final boolean allowInstant = (flags & Context.BIND_ALLOW_INSTANT) != 0;
@@ -2239,6 +2279,11 @@ public final class ActiveServices {
if ((flags & Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS) != 0) {
s.setAllowedBgActivityStartsByBinding(true);
}
+
+ if ((flags & Context.BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND) != 0) {
+ s.setAllowedBgFgsStartsByBinding(true);
+ }
+
if (s.app != null) {
updateServiceClientActivitiesLocked(s.app, c, true);
}
@@ -2256,7 +2301,6 @@ public final class ActiveServices {
return 0;
}
}
-
setFgsRestrictionLocked(callingPackage, callingPid, callingUid, service, s, false);
if (s.app != null) {
@@ -3647,6 +3691,9 @@ public final class ActiveServices {
if ((c.flags & Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS) != 0) {
s.updateIsAllowedBgActivityStartsByBinding();
}
+ if ((c.flags & Context.BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND) != 0) {
+ s.updateIsAllowedBgFgsStartsByBinding();
+ }
if (s.app != null) {
updateServiceClientActivitiesLocked(s.app, c, true);
}
@@ -5113,13 +5160,22 @@ public final class ActiveServices {
}
if (ret == FGS_FEATURE_DENIED) {
+ for (int i = mAm.mProcessList.mLruProcesses.size() - 1; i >= 0; i--) {
+ final ProcessRecord pr = mAm.mProcessList.mLruProcesses.get(i);
+ if (pr.uid == callingUid) {
+ if (pr.areBackgroundActivityStartsAllowedByToken()) {
+ ret = FGS_FEATURE_ALLOWED_BY_ACTIVITY_TOKEN;
+ break;
+ }
+ }
+ }
+ }
+
+ if (ret == FGS_FEATURE_DENIED) {
if (r.app != null) {
ActiveInstrumentation instr = r.app.getActiveInstrumentation();
if (instr != null && instr.mHasBackgroundActivityStartsPermission) {
- ret = FGS_FEATURE_ALLOWED_BY_INSTR_PERMISSION;
- }
- if (r.app.areBackgroundActivityStartsAllowedByToken()) {
- ret = FGS_FEATURE_ALLOWED_BY_TOKEN;
+ ret = FGS_FEATURE_ALLOWED_BY_INSTR_BACKGROUND_ACTIVITY_PERMISSION;
}
}
}
@@ -5127,15 +5183,15 @@ public final class ActiveServices {
if (ret == FGS_FEATURE_DENIED) {
if (mAm.checkPermission(START_ACTIVITIES_FROM_BACKGROUND, callingPid, callingUid)
== PERMISSION_GRANTED) {
- ret = FGS_FEATURE_ALLOWED_BY_PERMISSION;
+ ret = FGS_FEATURE_ALLOWED_BY_BACKGROUND_ACTIVITY_PERMISSION;
}
}
if (ret == FGS_FEATURE_DENIED) {
- final boolean isWhiteListedPackage =
- mWhiteListAllowWhileInUsePermissionInFgs.contains(callingPackage);
- if (isWhiteListedPackage) {
- ret = FGS_FEATURE_ALLOWED_BY_WHITELIST;
+ final boolean isAllowedPackage =
+ mAllowListWhileInUsePermissionInFgs.contains(callingPackage);
+ if (isAllowedPackage) {
+ ret = FGS_FEATURE_ALLOWED_BY_ALLOWLIST;
}
}
@@ -5187,6 +5243,39 @@ public final class ActiveServices {
}
if (ret == FGS_FEATURE_DENIED) {
+ for (int i = mAm.mProcessList.mLruProcesses.size() - 1; i >= 0; i--) {
+ final ProcessRecord pr = mAm.mProcessList.mLruProcesses.get(i);
+ if (pr.uid == callingUid) {
+ if (pr.areBackgroundFgsStartsAllowedByToken()) {
+ ret = FGS_FEATURE_ALLOWED_BY_FGS_BINDING;
+ break;
+ } else {
+ final ActiveInstrumentation instr = pr.getActiveInstrumentation();
+ if (instr != null
+ && instr.mHasBackgroundForegroundServiceStartsPermission) {
+ ret = FGS_FEATURE_ALLOWED_BY_INSTR_BACKGROUND_FGS_PERMISSION;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (ret == FGS_FEATURE_DENIED) {
+ if (mAm.checkPermission(START_FOREGROUND_SERVICES_FROM_BACKGROUND, callingPid,
+ callingUid) == PERMISSION_GRANTED) {
+ ret = FGS_FEATURE_ALLOWED_BY_BACKGROUND_FGS_PERMISSION;
+ }
+ }
+
+ if (ret == FGS_FEATURE_DENIED) {
+ if (mAm.checkPermission(SYSTEM_ALERT_WINDOW, callingPid,
+ callingUid) == PERMISSION_GRANTED) {
+ ret = FGS_FEATURE_ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION;
+ }
+ }
+
+ if (ret == FGS_FEATURE_DENIED) {
if (mAm.mConstants.mFlagFgsStartTempAllowListEnabled
&& mAm.isOnDeviceIdleWhitelistLocked(r.appInfo.uid, false)) {
// uid is on DeviceIdleController's allowlist.
@@ -5217,26 +5306,36 @@ public final class ActiveServices {
return "DENIED";
case FGS_FEATURE_ALLOWED_BY_UID_STATE:
return "ALLOWED_BY_UID_STATE";
+ case FGS_FEATURE_ALLOWED_BY_PROC_STATE:
+ return "ALLOWED_BY_PROC_STATE";
case FGS_FEATURE_ALLOWED_BY_UID_VISIBLE:
return "ALLOWED_BY_UID_VISIBLE";
case FGS_FEATURE_ALLOWED_BY_FLAG:
return "ALLOWED_BY_FLAG";
case FGS_FEATURE_ALLOWED_BY_SYSTEM_UID:
return "ALLOWED_BY_SYSTEM_UID";
- case FGS_FEATURE_ALLOWED_BY_INSTR_PERMISSION:
- return "ALLOWED_BY_INSTR_PERMISSION";
- case FGS_FEATURE_ALLOWED_BY_TOKEN:
- return "ALLOWED_BY_TOKEN";
- case FGS_FEATURE_ALLOWED_BY_PERMISSION:
- return "ALLOWED_BY_PERMISSION";
- case FGS_FEATURE_ALLOWED_BY_WHITELIST:
+ case FGS_FEATURE_ALLOWED_BY_INSTR_BACKGROUND_ACTIVITY_PERMISSION:
+ return "ALLOWED_BY_INSTR_BACKGROUND_ACTIVITY_PERMISSION";
+ case FGS_FEATURE_ALLOWED_BY_INSTR_BACKGROUND_FGS_PERMISSION:
+ return "ALLOWED_BY_INSTR_BACKGROUND_FGS_PERMISSION";
+ case FGS_FEATURE_ALLOWED_BY_ACTIVITY_TOKEN:
+ return "ALLOWED_BY_ACTIVITY_TOKEN";
+ case FGS_FEATURE_ALLOWED_BY_FGS_TOKEN:
+ return "ALLOWED_BY_FGS_TOKEN";
+ case FGS_FEATURE_ALLOWED_BY_BACKGROUND_ACTIVITY_PERMISSION:
+ return "ALLOWED_BY_BACKGROUND_ACTIVITY_PERMISSION";
+ case FGS_FEATURE_ALLOWED_BY_BACKGROUND_FGS_PERMISSION:
+ return "ALLOWED_BY_BACKGROUND_FGS_PERMISSION";
+ case FGS_FEATURE_ALLOWED_BY_ALLOWLIST:
return "ALLOWED_BY_WHITELIST";
case FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER:
return "ALLOWED_BY_DEVICE_OWNER";
- case FGS_FEATURE_ALLOWED_BY_PROC_STATE:
- return "ALLOWED_BY_PROC_STATE";
case FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST:
return "ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST";
+ case FGS_FEATURE_ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION:
+ return "ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION";
+ case FGS_FEATURE_ALLOWED_BY_FGS_BINDING:
+ return "ALLOWED_BY_FGS_BINDING";
default:
return "";
}
@@ -5271,11 +5370,10 @@ public final class ActiveServices {
NOTE_FOREGROUND_SERVICE_BG_LAUNCH, n.build(), UserHandle.ALL);
}
- private boolean isChangeEnabled(long changeId, ServiceRecord r) {
- boolean enabled = false;
- try {
- enabled = mPlatformCompat.isChangeEnabled(changeId, r.appInfo);
- } catch (RemoteException e) { }
- return enabled;
+ private boolean isBgFgsRestrictionEnabled(ServiceRecord r) {
+ if (mAm.mConstants.mFlagFgsStartRestrictionEnabled) {
+ return true;
+ }
+ return CompatChanges.isChangeEnabled(FGS_BG_START_RESTRICTION_CHANGE_ID, r.appInfo.uid);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 9eca15b241f4..75e8b13ccc0d 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -22,6 +22,7 @@ import static android.Manifest.permission.FILTER_EVENTS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
+import static android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND;
import static android.app.ActivityManager.INSTR_FLAG_DISABLE_HIDDEN_API_CHECKS;
import static android.app.ActivityManager.INSTR_FLAG_DISABLE_ISOLATED_STORAGE;
import static android.app.ActivityManager.INSTR_FLAG_DISABLE_TEST_API_CHECKS;
@@ -13321,15 +13322,22 @@ public class ActivityManagerService extends IActivityManager.Stub
// See if the caller is allowed to do this. Note we are checking against
// the actual real caller (not whoever provided the operation as say a
// PendingIntent), because that who is actually supplied the arguments.
- if (checkComponentPermission(
- android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST,
+ if (checkComponentPermission(CHANGE_DEVICE_IDLE_TEMP_WHITELIST,
+ realCallingPid, realCallingUid, -1, true)
+ != PackageManager.PERMISSION_GRANTED
+ && checkComponentPermission(START_ACTIVITIES_FROM_BACKGROUND,
+ realCallingPid, realCallingUid, -1, true)
+ != PackageManager.PERMISSION_GRANTED
+ && checkComponentPermission(START_FOREGROUND_SERVICES_FROM_BACKGROUND,
realCallingPid, realCallingUid, -1, true)
!= PackageManager.PERMISSION_GRANTED) {
String msg = "Permission Denial: " + intent.getAction()
+ " broadcast from " + callerPackage + " (pid=" + callingPid
+ ", uid=" + callingUid + ")"
+ " requires "
- + android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST;
+ + CHANGE_DEVICE_IDLE_TEMP_WHITELIST + " or "
+ + START_ACTIVITIES_FROM_BACKGROUND + " or "
+ + START_FOREGROUND_SERVICES_FROM_BACKGROUND;
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
@@ -14289,8 +14297,10 @@ public class ActivityManagerService extends IActivityManager.Stub
activeInstr.mHasBackgroundActivityStartsPermission = checkPermission(
START_ACTIVITIES_FROM_BACKGROUND, callingPid, callingUid)
== PackageManager.PERMISSION_GRANTED;
+ activeInstr.mHasBackgroundForegroundServiceStartsPermission = checkPermission(
+ START_FOREGROUND_SERVICES_FROM_BACKGROUND, callingPid, callingUid)
+ == PackageManager.PERMISSION_GRANTED;
activeInstr.mNoRestart = noRestart;
-
boolean disableHiddenApiChecks = ai.usesNonSdkApi()
|| (flags & INSTR_FLAG_DISABLE_HIDDEN_API_CHECKS) != 0;
boolean disableTestApiChecks = disableHiddenApiChecks
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index 93dd1aa37a11..fdc0f5949da8 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -37,13 +37,14 @@ import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.BatteryStatsImpl;
+import com.android.internal.power.MeasuredEnergyArray;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.function.pooled.PooledLambda;
-import java.util.concurrent.ExecutionException;
import libcore.util.EmptyArray;
import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
@@ -103,6 +104,9 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
private boolean mOnBatteryScreenOff;
@GuardedBy("this")
+ private int mScreenState;
+
+ @GuardedBy("this")
private boolean mUseLatestStates = true;
@GuardedBy("this")
@@ -194,15 +198,17 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
}
@Override
- public Future<?> scheduleCpuSyncDueToScreenStateChange(
- boolean onBattery, boolean onBatteryScreenOff) {
+ public Future<?> scheduleSyncDueToScreenStateChange(
+ int flags, boolean onBattery, boolean onBatteryScreenOff, int screenState) {
synchronized (BatteryExternalStatsWorker.this) {
if (mCurrentFuture == null || (mUpdateFlags & UPDATE_CPU) == 0) {
mOnBattery = onBattery;
mOnBatteryScreenOff = onBatteryScreenOff;
mUseLatestStates = false;
}
- return scheduleSyncLocked("screen-state", UPDATE_CPU);
+ // always update screen state
+ mScreenState = screenState;
+ return scheduleSyncLocked("screen-state", flags);
}
}
@@ -332,6 +338,7 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
final int[] uidsToRemove;
final boolean onBattery;
final boolean onBatteryScreenOff;
+ final int screenState;
final boolean useLatestStates;
synchronized (BatteryExternalStatsWorker.this) {
updateFlags = mUpdateFlags;
@@ -339,6 +346,7 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
uidsToRemove = mUidsToRemove.size() > 0 ? mUidsToRemove.toArray() : EmptyArray.INT;
onBattery = mOnBattery;
onBatteryScreenOff = mOnBatteryScreenOff;
+ screenState = mScreenState;
useLatestStates = mUseLatestStates;
mUpdateFlags = 0;
mCurrentReason = null;
@@ -360,7 +368,7 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
}
try {
updateExternalStatsLocked(reason, updateFlags, onBattery,
- onBatteryScreenOff, useLatestStates);
+ onBatteryScreenOff, screenState, useLatestStates);
} finally {
if (DEBUG) {
Slog.d(TAG, "end updateExternalStatsSync");
@@ -402,13 +410,14 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
};
@GuardedBy("mWorkerLock")
- private void updateExternalStatsLocked(final String reason, int updateFlags,
- boolean onBattery, boolean onBatteryScreenOff, boolean useLatestStates) {
+ private void updateExternalStatsLocked(final String reason, int updateFlags, boolean onBattery,
+ boolean onBatteryScreenOff, int screenState, boolean useLatestStates) {
// We will request data from external processes asynchronously, and wait on a timeout.
SynchronousResultReceiver wifiReceiver = null;
SynchronousResultReceiver bluetoothReceiver = null;
CompletableFuture<ModemActivityInfo> modemFuture = CompletableFuture.completedFuture(null);
boolean railUpdated = false;
+ MeasuredEnergyArray energyArray = null;
if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_WIFI) != 0) {
// We were asked to fetch WiFi data.
@@ -486,6 +495,13 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
}
}
+ if ((updateFlags & UPDATE_ENERGY) != 0) {
+ synchronized (mStats) {
+ // TODO(b/172934873) evaluate a safe way to query the HAL without holding mStats
+ energyArray = mStats.getEnergyConsumptionDataLocked();
+ }
+ }
+
final WifiActivityEnergyInfo wifiInfo = awaitControllerInfo(wifiReceiver);
final BluetoothActivityEnergyInfo bluetoothInfo = awaitControllerInfo(bluetoothReceiver);
ModemActivityInfo modemInfo = null;
@@ -533,6 +549,11 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
Slog.w(TAG, "bluetooth info is invalid: " + bluetoothInfo);
}
}
+
+ if ((updateFlags & UPDATE_ENERGY) != 0 && energyArray != null) {
+ // Always use what BatteryExternalStatsWorker thinks screenState is.
+ mStats.updateMeasuredEnergyStatsLocked(energyArray, screenState);
+ }
}
// WiFi and Modem state are updated without the mStats lock held, because they
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index ed2faf992e0e..46e16bcbb1b6 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -21,6 +21,8 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.hardware.power.stats.EnergyConsumerId;
+import android.hardware.power.stats.EnergyConsumerResult;
import android.os.BatteryStats;
import android.os.BatteryStatsInternal;
import android.os.Binder;
@@ -59,6 +61,7 @@ import com.android.internal.os.BinderCallsStats;
import com.android.internal.os.PowerProfile;
import com.android.internal.os.RailStats;
import com.android.internal.os.RpmStats;
+import com.android.internal.power.MeasuredEnergyArray;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.ParseUtils;
@@ -66,6 +69,7 @@ import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.LocalServices;
import com.android.server.Watchdog;
import com.android.server.pm.UserManagerInternal;
+import com.android.server.powerstats.PowerStatsHALWrapper;
import java.io.File;
import java.io.FileDescriptor;
@@ -90,7 +94,7 @@ import java.util.concurrent.Future;
public final class BatteryStatsService extends IBatteryStats.Stub
implements PowerManagerInternal.LowPowerModeListener,
BatteryStatsImpl.PlatformIdleStateCallback,
- BatteryStatsImpl.RailEnergyDataCallback,
+ BatteryStatsImpl.MeasuredEnergyRetriever,
Watchdog.Monitor {
static final String TAG = "BatteryStatsService";
static final boolean DBG = false;
@@ -115,6 +119,8 @@ public final class BatteryStatsService extends IBatteryStats.Stub
private CharBuffer mUtf16BufferStat = CharBuffer.allocate(MAX_LOW_POWER_STATS_SIZE);
private static final int MAX_LOW_POWER_STATS_SIZE = 4096;
+ private final PowerStatsHALWrapper.IPowerStatsHALWrapper mPowerStatsHALWrapper;
+
private final HandlerThread mHandlerThread;
private final Handler mHandler;
private final Object mLock = new Object();
@@ -186,6 +192,43 @@ public final class BatteryStatsService extends IBatteryStats.Stub
}
}
+ @Override
+ public MeasuredEnergyArray getEnergyConsumptionData() {
+ final EnergyConsumerResult[] results = mPowerStatsHALWrapper.getEnergyConsumed(new int[0]);
+ if (results == null) return null;
+ final int size = results.length;
+ final int[] subsystems = new int[size];
+ final long[] energyUJ = new long[size];
+
+ for (int i = 0; i < size; i++) {
+ final EnergyConsumerResult consumer = results[i];
+ final int subsystem;
+ switch (consumer.energyConsumerId) {
+ case EnergyConsumerId.DISPLAY:
+ subsystem = MeasuredEnergyArray.SUBSYSTEM_DISPLAY;
+ break;
+ default:
+ continue;
+ }
+ subsystems[i] = subsystem;
+ energyUJ[i] = consumer.energyUWs;
+ }
+ return new MeasuredEnergyArray() {
+ @Override
+ public int getSubsystem(int index) {
+ return subsystems[index];
+ }
+ @Override
+ public long getEnergy(int index) {
+ return energyUJ[index];
+ }
+ @Override
+ public int size() {
+ return size;
+ }
+ };
+ }
+
BatteryStatsService(Context context, File systemDir, Handler handler) {
// BatteryStatsImpl expects the ActivityManagerService handler, so pass that one through.
mContext = context;
@@ -202,6 +245,12 @@ public final class BatteryStatsService extends IBatteryStats.Stub
mHandlerThread = new HandlerThread("batterystats-handler");
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper());
+
+ // TODO(b/173077356): Replace directly calling the HAL with PowerStatsService queries
+ // Make sure to init Hal Wrapper before creating BatteryStatsImpl.
+ mPowerStatsHALWrapper = new PowerStatsHALWrapper.PowerStatsHALWrapperImpl();
+ mPowerStatsHALWrapper.initialize();
+
mStats = new BatteryStatsImpl(systemDir, handler, this,
this, mUserManagerUserInfoProvider);
mWorker = new BatteryExternalStatsWorker(context, mStats);
@@ -1963,6 +2012,15 @@ public final class BatteryStatsService extends IBatteryStats.Stub
}
}
+ private void dumpMeasuredEnergyStats(PrintWriter pw) {
+ // Wait for the completion of pending works if there is any
+ awaitCompletion();
+ syncStats("dump", BatteryExternalStatsWorker.UPDATE_ENERGY);
+ synchronized (mStats) {
+ mStats.dumpMeasuredEnergyStatsLocked(pw);
+ }
+ }
+
private int doEnableOrDisable(PrintWriter pw, int i, String[] args, boolean enable) {
i++;
if (i >= args.length) {
@@ -2103,6 +2161,9 @@ public final class BatteryStatsService extends IBatteryStats.Stub
} else if ("--cpu".equals(arg)) {
dumpCpuStats(pw);
return;
+ } else if ("--measured-energy".equals(arg)) {
+ dumpMeasuredEnergyStats(pw);
+ return;
} else if ("-a".equals(arg)) {
flags |= BatteryStats.DUMP_VERBOSE;
} else if (arg.length() > 0 && arg.charAt(0) == '-'){
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 1b06dd90df83..cf4adc65a7fc 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -359,6 +359,8 @@ class ProcessRecord implements WindowProcessListener {
// It must obtain the proc state from a persistent/top process or FGS, not transitive.
int mAllowStartFgsState = PROCESS_STATE_NONEXISTENT;
+ private final ArraySet<Binder> mBackgroundFgsStartTokens = new ArraySet<>();
+
void setStartParams(int startUid, HostingRecord hostingRecord, String seInfo,
long startTime) {
this.startUid = startUid;
@@ -1965,6 +1967,18 @@ class ProcessRecord implements WindowProcessListener {
}
}
+ public void addAllowBackgroundFgsStartsToken(Binder entity) {
+ mBackgroundFgsStartTokens.add(entity);
+ }
+
+ public void removeAllowBackgroundFgsStartsToken(Binder entity) {
+ mBackgroundFgsStartTokens.remove(entity);
+ }
+
+ public boolean areBackgroundFgsStartsAllowedByToken() {
+ return !mBackgroundFgsStartTokens.isEmpty();
+ }
+
ErrorDialogController getDialogController() {
return mDialogController;
}
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 364ad21b93cf..e129561b8bc5 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -147,6 +147,10 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
@GuardedBy("ams")
private List<IBinder> mBgActivityStartsByStartOriginatingTokens = new ArrayList<>();
+ // any current binding to this service has BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND
+ // flag? if true, the process can start FGS from background.
+ boolean mIsAllowedBgFgsStartsByBinding;
+
// allow while-in-use permissions in foreground service or not.
// while-in-use permissions in FGS started from background might be restricted.
boolean mAllowWhileInUsePermissionInFgs;
@@ -418,6 +422,10 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
pw.print(prefix); pw.print("mIsAllowedBgActivityStartsByStart=");
pw.println(mIsAllowedBgActivityStartsByStart);
}
+ if (mIsAllowedBgFgsStartsByBinding) {
+ pw.print(prefix); pw.print("mIsAllowedBgFgsStartsByBinding=");
+ pw.println(mIsAllowedBgFgsStartsByBinding);
+ }
pw.print(prefix); pw.print("allowWhileInUsePermissionInFgs=");
pw.println(mAllowWhileInUsePermissionInFgs);
pw.print(prefix); pw.print("recentCallingPackage=");
@@ -600,6 +608,11 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
} else {
_proc.removeAllowBackgroundActivityStartsToken(this);
}
+ if (mIsAllowedBgFgsStartsByBinding) {
+ _proc.addAllowBackgroundFgsStartsToken(this);
+ } else {
+ _proc.removeAllowBackgroundFgsStartsToken(this);
+ }
}
if (app != null && app != _proc) {
// If the old app is allowed to start bg activities because of a service start, leave it
@@ -686,11 +699,34 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
setAllowedBgActivityStartsByBinding(isAllowedByBinding);
}
+ void updateIsAllowedBgFgsStartsByBinding() {
+ boolean isAllowedByBinding = false;
+ for (int conni = connections.size() - 1; conni >= 0; conni--) {
+ ArrayList<ConnectionRecord> cr = connections.valueAt(conni);
+ for (int i = 0; i < cr.size(); i++) {
+ if ((cr.get(i).flags
+ & Context.BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND) != 0) {
+ isAllowedByBinding = true;
+ break;
+ }
+ }
+ if (isAllowedByBinding) {
+ break;
+ }
+ }
+ setAllowedBgFgsStartsByBinding(isAllowedByBinding);
+ }
+
void setAllowedBgActivityStartsByBinding(boolean newValue) {
mIsAllowedBgActivityStartsByBinding = newValue;
updateParentProcessBgActivityStartsToken();
}
+ void setAllowedBgFgsStartsByBinding(boolean newValue) {
+ mIsAllowedBgFgsStartsByBinding = newValue;
+ updateParentProcessBgFgsStartsToken();
+ }
+
/**
* Called when the service is started with allowBackgroundActivityStarts set. We allow
* it for background activity starts, setting up a callback to remove this ability after a
@@ -777,6 +813,17 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
}
}
+ private void updateParentProcessBgFgsStartsToken() {
+ if (app == null) {
+ return;
+ }
+ if (mIsAllowedBgFgsStartsByBinding) {
+ app.addAllowBackgroundFgsStartsToken(this);
+ } else {
+ app.removeAllowBackgroundFgsStartsToken(this);
+ }
+ }
+
/**
* Returns the originating token if that's the only reason background activity starts are
* allowed. In order for that to happen the service has to be allowed only due to starts, since
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index a471664b19b7..8494e515a406 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -500,7 +500,11 @@ public class BiometricService extends SystemService {
final List<SensorPropertiesInternal> sensors = new ArrayList<>();
for (BiometricSensor sensor : mSensors) {
- sensors.add(sensor.impl.getSensorProperties(opPackageName));
+ // Explicitly re-create as the super class, since AIDL doesn't play nicely with
+ // "List<? extends SensorPropertiesInternal> ...
+ final SensorPropertiesInternal prop = SensorPropertiesInternal
+ .from(sensor.impl.getSensorProperties(opPackageName));
+ sensors.add(prop);
}
return sensors;
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
index 36796b842410..cc9298603a3e 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
@@ -65,7 +65,6 @@ import java.util.List;
* Provider for a single instance of the {@link IFace} HAL.
*/
public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
- private static final String TAG = "FaceProvider";
private static final int ENROLL_TIMEOUT_SEC = 75;
private boolean mTestHalEnabled;
@@ -88,7 +87,7 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
public void onTaskStackChanged() {
mHandler.post(() -> {
for (int i = 0; i < mSensors.size(); i++) {
- final ClientMonitor<?> client = mSensors.get(i).getScheduler()
+ final ClientMonitor<?> client = mSensors.valueAt(i).getScheduler()
.getCurrentClient();
if (!(client instanceof AuthenticationClient)) {
Slog.e(getTag(), "Task stack changed for client: " + client);
@@ -108,7 +107,7 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
&& !client.isAlreadyDone()) {
Slog.e(getTag(), "Stopping background authentication, top: "
+ topPackage + " currentClient: " + client);
- mSensors.get(i).getScheduler()
+ mSensors.valueAt(i).getScheduler()
.cancelAuthentication(client.getToken());
}
}
@@ -550,12 +549,13 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
JSONObject dump = new JSONObject();
try {
- dump.put("service", "Face Manager");
+ dump.put("service", getTag());
JSONArray sets = new JSONArray();
for (UserInfo user : UserManager.get(mContext).getUsers()) {
final int userId = user.getUserHandle().getIdentifier();
- final int c = FaceUtils.getInstance().getBiometricsForUser(mContext, userId).size();
+ final int c = FaceUtils.getInstance(sensorId)
+ .getBiometricsForUser(mContext, userId).size();
JSONObject set = new JSONObject();
set.put("id", userId);
set.put("count", c);
@@ -574,7 +574,7 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
dump.put("prints", sets);
} catch (JSONException e) {
- Slog.e(TAG, "dump formatting failure", e);
+ Slog.e(getTag(), "dump formatting failure", e);
}
pw.println(dump);
pw.println("HAL deaths since last reboot: " + performanceTracker.getHALDeathCount());
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/TestSession.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/TestSession.java
index 9707eddfee74..fbc26c6498b3 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/TestSession.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/TestSession.java
@@ -24,7 +24,6 @@ import android.hardware.common.NativeHandle;
import android.hardware.keymaster.HardwareAuthToken;
import android.os.Binder;
import android.os.IBinder;
-import android.os.RemoteException;
/**
* Test session that provides mostly no-ops.
@@ -59,7 +58,7 @@ public class TestSession extends ISession.Stub {
public ICancellationSignal authenticate(int cookie, long operationId) {
return new ICancellationSignal() {
@Override
- public void cancel() throws RemoteException {
+ public void cancel() {
mHalSessionCallback.onError(Error.CANCELED, 0 /* vendorCode */);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
index c57ab505ca2a..d384bc645d61 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
@@ -796,7 +796,7 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
JSONObject dump = new JSONObject();
try {
- dump.put("service", "Face Manager");
+ dump.put("service", TAG);
JSONArray sets = new JSONArray();
for (UserInfo user : UserManager.get(mContext).getUsers()) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index db34d1444650..98c32cbcfc4a 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -53,6 +53,10 @@ import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDisp
import com.android.server.biometrics.sensors.fingerprint.ServiceProvider;
import com.android.server.biometrics.sensors.fingerprint.Udfps;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -84,7 +88,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
public void onTaskStackChanged() {
mHandler.post(() -> {
for (int i = 0; i < mSensors.size(); i++) {
- final ClientMonitor<?> client = mSensors.get(i).getScheduler()
+ final ClientMonitor<?> client = mSensors.valueAt(i).getScheduler()
.getCurrentClient();
if (!(client instanceof AuthenticationClient)) {
Slog.e(getTag(), "Task stack changed for client: " + client);
@@ -104,7 +108,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
&& !client.isAlreadyDone()) {
Slog.e(getTag(), "Stopping background authentication, top: "
+ topPackage + " currentClient: " + client);
- mSensors.get(i).getScheduler()
+ mSensors.valueAt(i).getScheduler()
.cancelAuthentication(client.getToken());
}
}
@@ -593,7 +597,42 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
@Override
public void dumpInternal(int sensorId, @NonNull PrintWriter pw) {
+ PerformanceTracker performanceTracker =
+ PerformanceTracker.getInstanceForSensorId(sensorId);
+
+ JSONObject dump = new JSONObject();
+ try {
+ dump.put("service", getTag());
+
+ JSONArray sets = new JSONArray();
+ for (UserInfo user : UserManager.get(mContext).getUsers()) {
+ final int userId = user.getUserHandle().getIdentifier();
+ final int c = FingerprintUtils.getInstance(sensorId)
+ .getBiometricsForUser(mContext, userId).size();
+ JSONObject set = new JSONObject();
+ set.put("id", userId);
+ set.put("count", c);
+ set.put("accept", performanceTracker.getAcceptForUser(userId));
+ set.put("reject", performanceTracker.getRejectForUser(userId));
+ set.put("acquire", performanceTracker.getAcquireForUser(userId));
+ set.put("lockout", performanceTracker.getTimedLockoutForUser(userId));
+ set.put("permanentLockout", performanceTracker.getPermanentLockoutForUser(userId));
+ // cryptoStats measures statistics about secure fingerprint transactions
+ // (e.g. to unlock password storage, make secure purchases, etc.)
+ set.put("acceptCrypto", performanceTracker.getAcceptCryptoForUser(userId));
+ set.put("rejectCrypto", performanceTracker.getRejectCryptoForUser(userId));
+ set.put("acquireCrypto", performanceTracker.getAcquireCryptoForUser(userId));
+ sets.put(set);
+ }
+
+ dump.put("prints", sets);
+ } catch (JSONException e) {
+ Slog.e(getTag(), "dump formatting failure", e);
+ }
+ pw.println(dump);
+ pw.println("HAL deaths since last reboot: " + performanceTracker.getHALDeathCount());
+ mSensors.get(sensorId).getScheduler().dump(pw);
}
@NonNull
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/TestSession.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/TestSession.java
index d6378780594f..ddae1107ff77 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/TestSession.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/TestSession.java
@@ -18,8 +18,11 @@ package com.android.server.biometrics.sensors.fingerprint.aidl;
import android.annotation.NonNull;
import android.hardware.biometrics.common.ICancellationSignal;
+import android.hardware.biometrics.face.Error;
import android.hardware.biometrics.fingerprint.ISession;
import android.hardware.keymaster.HardwareAuthToken;
+import android.os.Binder;
+import android.os.IBinder;
import android.util.Slog;
/**
@@ -37,24 +40,32 @@ class TestSession extends ISession.Stub {
@Override
public void generateChallenge(int cookie, int timeoutSec) {
-
+ mHalSessionCallback.onChallengeGenerated(0 /* challenge */);
}
@Override
public void revokeChallenge(int cookie, long challenge) {
-
+ mHalSessionCallback.onChallengeRevoked(challenge);
}
@Override
public ICancellationSignal enroll(int cookie, HardwareAuthToken hat) {
- Slog.d(TAG, "enroll");
return null;
}
@Override
public ICancellationSignal authenticate(int cookie, long operationId) {
- Slog.d(TAG, "authenticate");
- return null;
+ return new ICancellationSignal() {
+ @Override
+ public void cancel() {
+ mHalSessionCallback.onError(Error.CANCELED, 0 /* vendorCode */);
+ }
+
+ @Override
+ public IBinder asBinder() {
+ return new Binder();
+ }
+ };
}
@Override
@@ -86,7 +97,7 @@ class TestSession extends ISession.Stub {
@Override
public void resetLockout(int cookie, HardwareAuthToken hat) {
-
+ mHalSessionCallback.onLockoutCleared();
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
index 11372a30599d..f38dd092007a 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
@@ -776,7 +776,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
JSONObject dump = new JSONObject();
try {
- dump.put("service", "Fingerprint Manager");
+ dump.put("service", TAG);
JSONArray sets = new JSONArray();
for (UserInfo user : UserManager.get(mContext).getUsers()) {
diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
index fe6500e8942c..468d8259db18 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
@@ -22,6 +22,7 @@ import android.util.DisplayMetrics;
import android.view.Display;
import android.view.DisplayAddress;
import android.view.DisplayCutout;
+import android.view.DisplayEventReceiver;
import android.view.Surface;
import java.util.Arrays;
@@ -333,6 +334,9 @@ final class DisplayDeviceInfo {
*/
public String ownerPackageName;
+ public DisplayEventReceiver.FrameRateOverride[] frameRateOverrides =
+ new DisplayEventReceiver.FrameRateOverride[0];
+
public void setAssumedDensityForExternalDisplay(int width, int height) {
densityDpi = Math.min(width, height) * DisplayMetrics.DENSITY_XHIGH / 1080;
// Technically, these values should be smaller than the apparent density
@@ -386,7 +390,8 @@ final class DisplayDeviceInfo {
|| !Objects.equals(address, other.address)
|| !Objects.equals(deviceProductInfo, other.deviceProductInfo)
|| ownerUid != other.ownerUid
- || !Objects.equals(ownerPackageName, other.ownerPackageName)) {
+ || !Objects.equals(ownerPackageName, other.ownerPackageName)
+ || !Objects.equals(frameRateOverrides, other.frameRateOverrides)) {
diff |= DIFF_OTHER;
}
return diff;
@@ -425,6 +430,7 @@ final class DisplayDeviceInfo {
state = other.state;
ownerUid = other.ownerUid;
ownerPackageName = other.ownerPackageName;
+ frameRateOverrides = other.frameRateOverrides;
}
// For debugging purposes
@@ -461,6 +467,10 @@ final class DisplayDeviceInfo {
sb.append(", owner ").append(ownerPackageName);
sb.append(" (uid ").append(ownerUid).append(")");
}
+ sb.append(", frameRateOverride ");
+ for (DisplayEventReceiver.FrameRateOverride frameRateOverride : frameRateOverrides) {
+ sb.append(frameRateOverride).append(" ");
+ }
sb.append(flagsToString(flags));
sb.append("}");
return sb.toString();
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 4e60f1ff929e..29b413d921e1 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -37,6 +37,9 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.AppOpsManager;
+import android.app.compat.CompatChanges;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
@@ -83,7 +86,9 @@ import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
+import android.sysprop.DisplayProperties;
import android.text.TextUtils;
+import android.util.ArraySet;
import android.util.EventLog;
import android.util.IntArray;
import android.util.Pair;
@@ -92,6 +97,7 @@ import android.util.SparseArray;
import android.util.SparseIntArray;
import android.util.Spline;
import android.view.Display;
+import android.view.DisplayEventReceiver;
import android.view.DisplayInfo;
import android.view.IDisplayFoldListener;
import android.view.Surface;
@@ -114,6 +120,7 @@ import com.android.server.wm.WindowManagerInternal;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Optional;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Consumer;
@@ -181,6 +188,7 @@ public final class DisplayManagerService extends SystemService {
private static final int MSG_REQUEST_TRAVERSAL = 4;
private static final int MSG_UPDATE_VIEWPORT = 5;
private static final int MSG_LOAD_BRIGHTNESS_CONFIGURATION = 6;
+ private static final int MSG_DELIVER_DISPLAY_EVENT_FRAME_RATE_OVERRIDE = 7;
private final Context mContext;
private final DisplayManagerHandler mHandler;
@@ -357,6 +365,30 @@ public final class DisplayManagerService extends SystemService {
// Received notifications of the display-fold action
private DisplayFoldListener mDisplayFoldListener;
+ private final boolean mAllowNonNativeRefreshRateOverride;
+
+ private static final float THRESHOLD_FOR_REFRESH_RATES_DIVIDERS = 0.1f;
+
+ /**
+ * Applications use {@link android.view.Display#getRefreshRate} and
+ * {@link android.view.Display.Mode#getRefreshRate} to know what is the display refresh rate.
+ * Starting with Android S, the platform might throttle down applications frame rate to a
+ * divisor of the refresh rate if it is more preferable (for example if the application called
+ * to {@link android.view.Surface#setFrameRate}).
+ * Applications will experience {@link android.view.Choreographer#postFrameCallback} callbacks
+ * and backpressure at the throttled frame rate.
+ *
+ * {@link android.view.Display#getRefreshRate} will always return the application frame rate
+ * and not the physical display refresh rate to allow applications to do frame pacing correctly.
+ *
+ * {@link android.view.Display.Mode#getRefreshRate} will return the application frame rate if
+ * compiled to a previous release and starting with Android S it will return the physical
+ * display refresh rate.
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.S)
+ static final long DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE = 170503758L;
+
public DisplayManagerService(Context context) {
this(context, new Injector());
}
@@ -389,6 +421,7 @@ public final class DisplayManagerService extends SystemService {
mCurrentUserId = UserHandle.USER_SYSTEM;
ColorSpace[] colorSpaces = SurfaceControl.getCompositionColorSpaces();
mWideColorSpace = colorSpaces[1];
+ mAllowNonNativeRefreshRateOverride = mInjector.getAllowNonNativeRefreshRateOverride();
mSystemReady = false;
}
@@ -677,11 +710,82 @@ public final class DisplayManagerService extends SystemService {
Settings.Secure.MINIMAL_POST_PROCESSING_ALLOWED, 1, UserHandle.USER_CURRENT) != 0;
}
+ private DisplayInfo getDisplayInfoForFrameRateOverride(DisplayEventReceiver.FrameRateOverride[]
+ frameRateOverrides, DisplayInfo info, int callingUid) {
+ float frameRateHz = 0;
+ for (DisplayEventReceiver.FrameRateOverride frameRateOverride : frameRateOverrides) {
+ if (frameRateOverride.uid == callingUid) {
+ frameRateHz = frameRateOverride.frameRateHz;
+ break;
+ }
+ }
+ if (frameRateHz == 0) {
+ return info;
+ }
+
+ // Override the refresh rate only if it is a divider of the current
+ // refresh rate. This calculation needs to be in sync with the native code
+ // in RefreshRateConfigs::getRefreshRateDividerForUid
+ Display.Mode currentMode = info.getMode();
+ float numPeriods = currentMode.getRefreshRate() / frameRateHz;
+ float numPeriodsRound = Math.round(numPeriods);
+ if (Math.abs(numPeriods - numPeriodsRound) > THRESHOLD_FOR_REFRESH_RATES_DIVIDERS) {
+ return info;
+ }
+ frameRateHz = currentMode.getRefreshRate() / numPeriodsRound;
+
+ DisplayInfo overriddenInfo = new DisplayInfo();
+ overriddenInfo.copyFrom(info);
+ for (Display.Mode mode : info.supportedModes) {
+ if (!mode.equalsExceptRefreshRate(currentMode)) {
+ continue;
+ }
+
+ if (mode.getRefreshRate() >= frameRateHz - THRESHOLD_FOR_REFRESH_RATES_DIVIDERS
+ && mode.getRefreshRate()
+ <= frameRateHz + THRESHOLD_FOR_REFRESH_RATES_DIVIDERS) {
+ if (DEBUG) {
+ Slog.d(TAG, "found matching modeId " + mode.getModeId());
+ }
+ overriddenInfo.refreshRateOverride = mode.getRefreshRate();
+
+ if (!CompatChanges.isChangeEnabled(DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE,
+ callingUid)) {
+ overriddenInfo.modeId = mode.getModeId();
+ }
+ return overriddenInfo;
+ }
+ }
+
+ if (mAllowNonNativeRefreshRateOverride) {
+ overriddenInfo.refreshRateOverride = frameRateHz;
+ if (!CompatChanges.isChangeEnabled(DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE,
+ callingUid)) {
+ overriddenInfo.supportedModes = Arrays.copyOf(info.supportedModes,
+ info.supportedModes.length + 1);
+ overriddenInfo.supportedModes[overriddenInfo.supportedModes.length - 1] =
+ new Display.Mode(Display.DISPLAY_MODE_ID_FOR_FRAME_RATE_OVERRIDE,
+ currentMode.getPhysicalWidth(), currentMode.getPhysicalHeight(),
+ overriddenInfo.refreshRateOverride);
+ overriddenInfo.modeId =
+ overriddenInfo.supportedModes[overriddenInfo.supportedModes.length - 1]
+ .getModeId();
+ }
+ return overriddenInfo;
+ }
+
+
+
+ return info;
+ }
+
private DisplayInfo getDisplayInfoInternal(int displayId, int callingUid) {
synchronized (mSyncRoot) {
LogicalDisplay display = mLogicalDisplayMapper.getLocked(displayId);
if (display != null) {
- DisplayInfo info = display.getDisplayInfoLocked();
+ DisplayInfo info =
+ getDisplayInfoForFrameRateOverride(display.getFrameRateOverrides(),
+ display.getDisplayInfoLocked(), callingUid);
if (info.hasAccess(callingUid)
|| isUidPresentOnDisplayInternal(callingUid, displayId)) {
return info;
@@ -691,14 +795,15 @@ public final class DisplayManagerService extends SystemService {
}
}
- private void registerCallbackInternal(IDisplayManagerCallback callback, int callingPid) {
+ private void registerCallbackInternal(IDisplayManagerCallback callback, int callingPid,
+ int callingUid) {
synchronized (mSyncRoot) {
if (mCallbacks.get(callingPid) != null) {
throw new SecurityException("The calling process has already "
+ "registered an IDisplayManagerCallback.");
}
- CallbackRecord record = new CallbackRecord(callingPid, callback);
+ CallbackRecord record = new CallbackRecord(callingPid, callingUid, callback);
try {
IBinder binder = callback.asBinder();
binder.linkToDeath(record, 0);
@@ -1034,6 +1139,16 @@ public final class DisplayManagerService extends SystemService {
scheduleTraversalLocked(false);
}
+ private void handleLogicalDisplayFrameRateOverridesChangedLocked(
+ @NonNull LogicalDisplay display) {
+ final int displayId = display.getDisplayIdLocked();
+ // We don't bother invalidating the display info caches here because any changes to the
+ // display info will trigger a cache invalidation inside of LogicalDisplay before we hit
+ // this point.
+ sendDisplayEventFrameRateOverrideLocked(displayId);
+ scheduleTraversalLocked(false);
+ }
+
private void handleLogicalDisplayRemovedLocked(@NonNull LogicalDisplay display) {
final int displayId = display.getDisplayIdLocked();
mDisplayPowerControllers.delete(displayId);
@@ -1545,6 +1660,12 @@ public final class DisplayManagerService extends SystemService {
mHandler.sendMessage(msg);
}
+ private void sendDisplayEventFrameRateOverrideLocked(int displayId) {
+ Message msg = mHandler.obtainMessage(MSG_DELIVER_DISPLAY_EVENT_FRAME_RATE_OVERRIDE,
+ displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
+ mHandler.sendMessage(msg);
+ }
+
// Requests that performTraversals be called at a
// later time to apply changes to surfaces and displays.
private void scheduleTraversalLocked(boolean inTraversal) {
@@ -1558,7 +1679,7 @@ public final class DisplayManagerService extends SystemService {
// Runs on Handler thread.
// Delivers display event notifications to callbacks.
- private void deliverDisplayEvent(int displayId, int event) {
+ private void deliverDisplayEvent(int displayId, ArraySet<Integer> uids, int event) {
if (DEBUG) {
Slog.d(TAG, "Delivering display event: displayId="
+ displayId + ", event=" + event);
@@ -1570,12 +1691,14 @@ public final class DisplayManagerService extends SystemService {
count = mCallbacks.size();
mTempCallbacks.clear();
for (int i = 0; i < count; i++) {
- mTempCallbacks.add(mCallbacks.valueAt(i));
+ if (uids == null || uids.contains(mCallbacks.valueAt(i).mUid)) {
+ mTempCallbacks.add(mCallbacks.valueAt(i));
+ }
}
}
// After releasing the lock, send the notifications out.
- for (int i = 0; i < count; i++) {
+ for (int i = 0; i < mTempCallbacks.size(); i++) {
mTempCallbacks.get(i).notifyDisplayEventAsync(displayId, event);
}
mTempCallbacks.clear();
@@ -1691,6 +1814,11 @@ public final class DisplayManagerService extends SystemService {
long getDefaultDisplayDelayTimeout() {
return WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT;
}
+
+ boolean getAllowNonNativeRefreshRateOverride() {
+ return DisplayProperties
+ .debug_allow_non_native_refresh_rate_override().orElse(false);
+ }
}
@VisibleForTesting
@@ -1760,7 +1888,7 @@ public final class DisplayManagerService extends SystemService {
break;
case MSG_DELIVER_DISPLAY_EVENT:
- deliverDisplayEvent(msg.arg1, msg.arg2);
+ deliverDisplayEvent(msg.arg1, null, msg.arg2);
break;
case MSG_REQUEST_TRAVERSAL:
@@ -1787,6 +1915,17 @@ public final class DisplayManagerService extends SystemService {
case MSG_LOAD_BRIGHTNESS_CONFIGURATION:
loadBrightnessConfiguration();
break;
+
+ case MSG_DELIVER_DISPLAY_EVENT_FRAME_RATE_OVERRIDE:
+ ArraySet<Integer> uids;
+ synchronized (mSyncRoot) {
+ int displayId = msg.arg1;
+ LogicalDisplay display = mLogicalDisplayMapper.getLocked(displayId);
+ uids = display.getPendingFrameRateOverrideUids();
+ display.clearPendingFrameRateOverrideUids();
+ }
+ deliverDisplayEvent(msg.arg1, uids, msg.arg2);
+ break;
}
}
}
@@ -1810,6 +1949,10 @@ public final class DisplayManagerService extends SystemService {
case LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_SWAPPED:
handleLogicalDisplaySwappedLocked(display);
break;
+
+ case LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED:
+ handleLogicalDisplayFrameRateOverridesChangedLocked(display);
+ break;
}
}
@@ -1823,12 +1966,14 @@ public final class DisplayManagerService extends SystemService {
private final class CallbackRecord implements DeathRecipient {
public final int mPid;
+ public final int mUid;
private final IDisplayManagerCallback mCallback;
public boolean mWifiDisplayScanRequested;
- public CallbackRecord(int pid, IDisplayManagerCallback callback) {
+ CallbackRecord(int pid, int uid, IDisplayManagerCallback callback) {
mPid = pid;
+ mUid = uid;
mCallback = callback;
}
@@ -1918,9 +2063,10 @@ public final class DisplayManagerService extends SystemService {
}
final int callingPid = Binder.getCallingPid();
+ final int callingUid = Binder.getCallingUid();
final long token = Binder.clearCallingIdentity();
try {
- registerCallbackInternal(callback, callingPid);
+ registerCallbackInternal(callback, callingPid, callingUid);
} finally {
Binder.restoreCallingIdentity(token);
}
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index f6578584cb18..74ea2d7114fc 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -208,6 +208,9 @@ final class LocalDisplayAdapter extends DisplayAdapter {
private DisplayDeviceConfig mDisplayDeviceConfig;
+ private DisplayEventReceiver.FrameRateOverride[] mFrameRateOverrides =
+ new DisplayEventReceiver.FrameRateOverride[0];
+
LocalDisplayDevice(IBinder displayToken, long physicalDisplayId,
SurfaceControl.DisplayInfo info, SurfaceControl.DisplayConfig[] configs,
int activeConfigId, SurfaceControl.DesiredDisplayConfigSpecs configSpecs,
@@ -625,6 +628,8 @@ final class LocalDisplayAdapter extends DisplayAdapter {
mInfo.name = getContext().getResources().getString(
com.android.internal.R.string.display_manager_hdmi_display_name);
}
+ mInfo.frameRateOverrides = mFrameRateOverrides;
+
// The display is trusted since it is created by system.
mInfo.flags |= DisplayDeviceInfo.FLAG_TRUSTED;
}
@@ -882,6 +887,13 @@ final class LocalDisplayAdapter extends DisplayAdapter {
}
}
+ public void onFrameRateOverridesChanged(
+ DisplayEventReceiver.FrameRateOverride[] overrides) {
+ if (updateFrameRateOverridesLocked(overrides)) {
+ updateDeviceInfoLocked();
+ }
+ }
+
public boolean updateActiveModeLocked(int activeConfigId) {
if (mActiveConfigId == activeConfigId) {
return false;
@@ -895,6 +907,16 @@ final class LocalDisplayAdapter extends DisplayAdapter {
return true;
}
+ public boolean updateFrameRateOverridesLocked(
+ DisplayEventReceiver.FrameRateOverride[] overrides) {
+ if (overrides.equals(mFrameRateOverrides)) {
+ return false;
+ }
+
+ mFrameRateOverrides = overrides;
+ return true;
+ }
+
public void requestColorModeLocked(int colorMode) {
if (mActiveColorMode == colorMode) {
return;
@@ -1102,23 +1124,39 @@ final class LocalDisplayAdapter extends DisplayAdapter {
public interface DisplayEventListener {
void onHotplug(long timestampNanos, long physicalDisplayId, boolean connected);
void onConfigChanged(long timestampNanos, long physicalDisplayId, int configId);
+ void onFrameRateOverridesChanged(long timestampNanos, long physicalDisplayId,
+ DisplayEventReceiver.FrameRateOverride[] overrides);
+
}
public static final class ProxyDisplayEventReceiver extends DisplayEventReceiver {
private final DisplayEventListener mListener;
ProxyDisplayEventReceiver(Looper looper, DisplayEventListener listener) {
- super(looper, VSYNC_SOURCE_APP, CONFIG_CHANGED_EVENT_DISPATCH);
+ super(looper, VSYNC_SOURCE_APP,
+ EVENT_REGISTRATION_CONFIG_CHANGED_FLAG
+ | EVENT_REGISTRATION_FRAME_RATE_OVERRIDE_FLAG);
mListener = listener;
}
+
+ @Override
public void onHotplug(long timestampNanos, long physicalDisplayId, boolean connected) {
mListener.onHotplug(timestampNanos, physicalDisplayId, connected);
}
+
+ @Override
public void onConfigChanged(long timestampNanos, long physicalDisplayId, int configId) {
mListener.onConfigChanged(timestampNanos, physicalDisplayId, configId);
}
+
+ @Override
+ public void onFrameRateOverridesChanged(long timestampNanos, long physicalDisplayId,
+ DisplayEventReceiver.FrameRateOverride[] overrides) {
+ mListener.onFrameRateOverridesChanged(timestampNanos, physicalDisplayId, overrides);
+ }
}
private final class LocalDisplayEventListener implements DisplayEventListener {
+ @Override
public void onHotplug(long timestampNanos, long physicalDisplayId, boolean connected) {
synchronized (getSyncRoot()) {
if (connected) {
@@ -1128,6 +1166,8 @@ final class LocalDisplayAdapter extends DisplayAdapter {
}
}
}
+
+ @Override
public void onConfigChanged(long timestampNanos, long physicalDisplayId, int configId) {
if (DEBUG) {
Slog.d(TAG, "onConfigChanged("
@@ -1147,5 +1187,26 @@ final class LocalDisplayAdapter extends DisplayAdapter {
device.onActiveDisplayConfigChangedLocked(configId);
}
}
+
+ @Override
+ public void onFrameRateOverridesChanged(long timestampNanos, long physicalDisplayId,
+ DisplayEventReceiver.FrameRateOverride[] overrides) {
+ if (DEBUG) {
+ Slog.d(TAG, "onFrameRateOverrideChanged(timestampNanos=" + timestampNanos
+ + ", physicalDisplayId=" + physicalDisplayId + " overrides="
+ + Arrays.toString(overrides) + ")");
+ }
+ synchronized (getSyncRoot()) {
+ LocalDisplayDevice device = mDevices.get(physicalDisplayId);
+ if (device == null) {
+ if (DEBUG) {
+ Slog.d(TAG, "Received frame rate override event for unhandled physical"
+ + " display: physicalDisplayId=" + physicalDisplayId);
+ }
+ return;
+ }
+ device.onFrameRateOverridesChanged(overrides);
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 979c3b871284..d80e1687f67f 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -20,8 +20,11 @@ import android.annotation.NonNull;
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.display.DisplayManagerInternal;
+import android.util.ArraySet;
import android.util.Slog;
+import android.util.SparseArray;
import android.view.Display;
+import android.view.DisplayEventReceiver;
import android.view.DisplayInfo;
import android.view.Surface;
import android.view.SurfaceControl;
@@ -123,10 +126,27 @@ final class LogicalDisplay {
*/
private boolean mIsEnabled = true;
+ /**
+ * The UID mappings for refresh rate override
+ */
+ private DisplayEventReceiver.FrameRateOverride[] mFrameRateOverrides;
+
+ /**
+ * Holds a set of UIDs that their frame rate override changed and needs to be notified
+ */
+ private ArraySet<Integer> mPendingFrameRateOverrideUids;
+
+ /**
+ * Temporary frame rate override list, used when needed.
+ */
+ private final SparseArray<Float> mTempFrameRateOverride;
+
public LogicalDisplay(int displayId, int layerStack, DisplayDevice primaryDisplayDevice) {
mDisplayId = displayId;
mLayerStack = layerStack;
mPrimaryDisplayDevice = primaryDisplayDevice;
+ mPendingFrameRateOverrideUids = new ArraySet<>();
+ mTempFrameRateOverride = new SparseArray<>();
}
/**
@@ -179,6 +199,27 @@ final class LogicalDisplay {
}
/**
+ * Returns the frame rate overrides list
+ */
+ public DisplayEventReceiver.FrameRateOverride[] getFrameRateOverrides() {
+ return mFrameRateOverrides;
+ }
+
+ /**
+ * Returns the list of uids that needs to be updated about their frame rate override
+ */
+ public ArraySet<Integer> getPendingFrameRateOverrideUids() {
+ return mPendingFrameRateOverrideUids;
+ }
+
+ /**
+ * Clears the list of uids that needs to be updated about their frame rate override
+ */
+ public void clearPendingFrameRateOverrideUids() {
+ mPendingFrameRateOverrideUids = new ArraySet<>();
+ }
+
+ /**
* @see DisplayManagerInternal#getNonOverrideDisplayInfo(int, DisplayInfo)
*/
void getNonOverrideDisplayInfoLocked(DisplayInfo outInfo) {
@@ -324,12 +365,40 @@ final class LogicalDisplay {
(deviceInfo.flags & DisplayDeviceInfo.FLAG_MASK_DISPLAY_CUTOUT) != 0;
mBaseDisplayInfo.displayCutout = maskCutout ? null : deviceInfo.displayCutout;
mBaseDisplayInfo.displayId = mDisplayId;
+ updateFrameRateOverrides(deviceInfo);
mPrimaryDisplayDeviceInfo = deviceInfo;
mInfo.set(null);
}
}
+ private void updateFrameRateOverrides(DisplayDeviceInfo deviceInfo) {
+ mTempFrameRateOverride.clear();
+ if (mFrameRateOverrides != null) {
+ for (DisplayEventReceiver.FrameRateOverride frameRateOverride
+ : mFrameRateOverrides) {
+ mTempFrameRateOverride.put(frameRateOverride.uid,
+ frameRateOverride.frameRateHz);
+ }
+ }
+ mFrameRateOverrides = deviceInfo.frameRateOverrides;
+ if (mFrameRateOverrides != null) {
+ for (DisplayEventReceiver.FrameRateOverride frameRateOverride
+ : mFrameRateOverrides) {
+ float refreshRate = mTempFrameRateOverride.get(frameRateOverride.uid, 0f);
+ if (refreshRate == 0 || frameRateOverride.frameRateHz != refreshRate) {
+ mTempFrameRateOverride.put(frameRateOverride.uid,
+ frameRateOverride.frameRateHz);
+ } else {
+ mTempFrameRateOverride.delete(frameRateOverride.uid);
+ }
+ }
+ }
+ for (int i = 0; i < mTempFrameRateOverride.size(); i++) {
+ mPendingFrameRateOverrideUids.add(mTempFrameRateOverride.keyAt(i));
+ }
+ }
+
/**
* Return the insets currently applied to the display.
*
@@ -638,5 +707,7 @@ final class LogicalDisplay {
pw.println("mBaseDisplayInfo=" + mBaseDisplayInfo);
pw.println("mOverrideDisplayInfo=" + mOverrideDisplayInfo);
pw.println("mRequestedMinimalPostProcessing=" + mRequestedMinimalPostProcessing);
+ pw.println("mFrameRateOverrides=" + Arrays.toString(mFrameRateOverrides));
+ pw.println("mPendingFrameRateOverrideUids=" + mPendingFrameRateOverrideUids);
}
}
diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
index 6b741709321c..cdcbb4f123a1 100644
--- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java
+++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
@@ -23,6 +23,7 @@ import android.text.TextUtils;
import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
+import android.view.DisplayEventReceiver;
import android.view.DisplayInfo;
import com.android.internal.util.IndentingPrintWriter;
@@ -52,6 +53,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
public static final int LOGICAL_DISPLAY_EVENT_CHANGED = 2;
public static final int LOGICAL_DISPLAY_EVENT_REMOVED = 3;
public static final int LOGICAL_DISPLAY_EVENT_SWAPPED = 4;
+ public static final int LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED = 5;
/**
* Temporary display info, used for comparing display configurations.
@@ -342,6 +344,8 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
mTempDisplayInfo.copyFrom(display.getDisplayInfoLocked());
display.getNonOverrideDisplayInfoLocked(mTempNonOverrideDisplayInfo);
+ DisplayEventReceiver.FrameRateOverride[] frameRatesOverrides =
+ display.getFrameRateOverrides();
display.updateLocked(mDisplayDeviceRepo);
if (!display.isValidLocked()) {
mLogicalDisplays.removeAt(i);
@@ -376,6 +380,9 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
final int eventMsg = TextUtils.equals(oldUniqueId, newUniqueId)
? LOGICAL_DISPLAY_EVENT_CHANGED : LOGICAL_DISPLAY_EVENT_SWAPPED;
mListener.onLogicalDisplayEventLocked(display, eventMsg);
+ } else if (!display.getPendingFrameRateOverrideUids().isEmpty()) {
+ mListener.onLogicalDisplayEventLocked(display,
+ LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED);
} else {
// While applications shouldn't know nor care about the non-overridden info, we
// still need to let WindowManager know so it can update its own internal state for
diff --git a/services/core/java/com/android/server/display/OverlayDisplayWindow.java b/services/core/java/com/android/server/display/OverlayDisplayWindow.java
index 49f0d35d2e78..cd3a453d5e64 100644
--- a/services/core/java/com/android/server/display/OverlayDisplayWindow.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayWindow.java
@@ -16,8 +16,6 @@
package com.android.server.display;
-import com.android.internal.util.DumpUtils;
-
import android.content.Context;
import android.graphics.SurfaceTexture;
import android.hardware.display.DisplayManager;
@@ -30,12 +28,14 @@ import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.TextureView;
+import android.view.TextureView.SurfaceTextureListener;
import android.view.ThreadedRenderer;
import android.view.View;
import android.view.WindowManager;
-import android.view.TextureView.SurfaceTextureListener;
import android.widget.TextView;
+import com.android.internal.util.DumpUtils;
+
import java.io.PrintWriter;
/**
@@ -319,7 +319,7 @@ final class OverlayDisplayWindow implements DumpUtils.Dump {
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture,
int width, int height) {
mListener.onWindowCreated(surfaceTexture,
- mDefaultDisplayInfo.getMode().getRefreshRate(),
+ mDefaultDisplayInfo.getRefreshRate(),
mDefaultDisplayInfo.presentationDeadlineNanos, mDefaultDisplayInfo.state);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 38807112576a..f76dec319379 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -21,7 +21,6 @@ import static android.Manifest.permission.MANAGE_DEVICE_ADMINS;
import static android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS;
import static android.Manifest.permission.REQUEST_DELETE_PACKAGES;
import static android.Manifest.permission.SET_HARMFUL_APP_WARNINGS;
-import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.MODE_DEFAULT;
import static android.app.AppOpsManager.MODE_IGNORED;
import static android.content.Intent.ACTION_MAIN;
@@ -44,7 +43,6 @@ import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKED_COMPAT;
import static android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
-import static android.content.pm.PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER;
import static android.content.pm.PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
import static android.content.pm.PackageManager.INSTALL_FAILED_BAD_PERMISSION_GROUP;
import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;
@@ -141,6 +139,7 @@ import android.annotation.AppIdInt;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.StringRes;
import android.annotation.UserIdInt;
import android.annotation.WorkerThread;
import android.app.ActivityManager;
@@ -1203,6 +1202,7 @@ public class PackageManagerService extends IPackageManager.Stub
public ViewCompiler viewCompiler;
public @Nullable String wellbeingPackage;
public @Nullable String retailDemoPackage;
+ public @Nullable String recentsPackage;
public ComponentName resolveComponentName;
public ArrayMap<String, AndroidPackage> packages;
public boolean enableFreeCacheV2;
@@ -1737,6 +1737,7 @@ public class PackageManagerService extends IPackageManager.Stub
final @Nullable String mSharedSystemSharedLibraryPackageName;
final @Nullable String mRetailDemoPackage;
final @Nullable String mOverlayConfigSignaturePackage;
+ final @Nullable String mRecentsPackage;
private final PackageUsage mPackageUsage = new PackageUsage();
private final CompilerStats mCompilerStats = new CompilerStats();
@@ -2169,7 +2170,7 @@ public class PackageManagerService extends IPackageManager.Stub
private void handlePackagePostInstall(PackageInstalledInfo res, boolean grantPermissions,
boolean killApp, boolean virtualPreload,
- String[] grantedPermissions, List<String> whitelistedRestrictedPermissions,
+ String[] grantedPermissions, List<String> allowlistedRestrictedPermissions,
int autoRevokePermissionsMode,
boolean launchedForRestore, String installerPackage,
IPackageInstallObserver2 installObserver, int dataLoaderType) {
@@ -2202,32 +2203,21 @@ public class PackageManagerService extends IPackageManager.Stub
res.removedInfo.sendPackageRemovedBroadcasts(killApp, false /*removedBySystem*/);
}
- // Allowlist any restricted permissions first as some may be runtime
- // that the installer requested to be granted at install time.
- if (whitelistedRestrictedPermissions != null
- && !whitelistedRestrictedPermissions.isEmpty()) {
- mPermissionManager.setAllowlistedRestrictedPermissions(res.pkg,
- whitelistedRestrictedPermissions, FLAG_PERMISSION_WHITELIST_INSTALLER,
- res.newUsers);
- }
-
- if (autoRevokePermissionsMode == MODE_ALLOWED
- || autoRevokePermissionsMode == MODE_IGNORED) {
- mPermissionManager.setAutoRevokeExempted(res.pkg,
- autoRevokePermissionsMode == MODE_IGNORED, res.newUsers);
- }
-
- // Now that we successfully installed the package, grant runtime
- // permissions if requested before broadcasting the install. Also
- // for legacy apps in permission review mode we clear the permission
- // review flag which is used to emulate runtime permissions for
- // legacy apps.
+ final List<String> grantedPermissionsList;
if (grantPermissions) {
- final int callingUid = Binder.getCallingUid();
- mPermissionManager.grantRequestedRuntimePermissions(res.pkg,
- grantedPermissions != null ? Arrays.asList(grantedPermissions) : null,
- res.newUsers);
+ if (grantedPermissions != null) {
+ grantedPermissionsList = Arrays.asList(grantedPermissions);
+ } else {
+ grantedPermissionsList = res.pkg.getRequestedPermissions();
+ }
+ } else {
+ grantedPermissionsList = Collections.emptyList();
+ }
+ if (allowlistedRestrictedPermissions == null) {
+ allowlistedRestrictedPermissions = Collections.emptyList();
}
+ mPermissionManager.onPackageInstalled(res.pkg, grantedPermissionsList,
+ allowlistedRestrictedPermissions, autoRevokePermissionsMode, res.newUsers);
final String installerPackageName =
res.installerPackageName != null
@@ -2980,6 +2970,7 @@ public class PackageManagerService extends IPackageManager.Stub
mSystemTextClassifierPackageName = testParams.systemTextClassifierPackage;
mWellbeingPackage = testParams.wellbeingPackage;
mRetailDemoPackage = testParams.retailDemoPackage;
+ mRecentsPackage = testParams.recentsPackage;
mDocumenterPackage = testParams.documenterPackage;
mConfiguratorPackage = testParams.configuratorPackage;
mAppPredictionServicePackage = testParams.appPredictionServicePackage;
@@ -3564,6 +3555,7 @@ public class PackageManagerService extends IPackageManager.Stub
mIncidentReportApproverPackage = getIncidentReportApproverPackageName();
mRetailDemoPackage = getRetailDemoPackageName();
mOverlayConfigSignaturePackage = getOverlayConfigSignaturePackageName();
+ mRecentsPackage = getRecentsPackageName();
// Now that we know all of the shared libraries, update all clients to have
// the correct library paths.
@@ -13676,9 +13668,8 @@ public class PackageManagerService extends IPackageManager.Stub
!= 0) {
whiteListedPermissions = pkgSetting.pkg.getRequestedPermissions();
}
- mPermissionManager.setAllowlistedRestrictedPermissions(pkgSetting.pkg,
- whiteListedPermissions, FLAG_PERMISSION_WHITELIST_INSTALLER,
- new int[] { userId });
+ mPermissionManager.onPackageInstalled(pkgSetting.pkg, Collections.emptyList(),
+ whiteListedPermissions, MODE_DEFAULT, new int[] { userId });
}
if (pkgSetting.pkg != null) {
@@ -21329,15 +21320,8 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public @Nullable String getAttentionServicePackageName() {
- final String flattenedComponentName =
- mContext.getString(R.string.config_defaultAttentionService);
- if (flattenedComponentName != null) {
- ComponentName componentName = ComponentName.unflattenFromString(flattenedComponentName);
- if (componentName != null && componentName.getPackageName() != null) {
- return ensureSystemPackageName(componentName.getPackageName());
- }
- }
- return null;
+ return ensureSystemPackageName(
+ getPackageFromComponentString(R.string.config_defaultAttentionService));
}
private @Nullable String getDocumenterPackageName() {
@@ -21372,17 +21356,8 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public String getAppPredictionServicePackageName() {
- String flattenedAppPredictionServiceComponentName =
- mContext.getString(R.string.config_defaultAppPredictionService);
- if (flattenedAppPredictionServiceComponentName == null) {
- return null;
- }
- ComponentName appPredictionServiceComponentName =
- ComponentName.unflattenFromString(flattenedAppPredictionServiceComponentName);
- if (appPredictionServiceComponentName == null) {
- return null;
- }
- return ensureSystemPackageName(appPredictionServiceComponentName.getPackageName());
+ return ensureSystemPackageName(
+ getPackageFromComponentString(R.string.config_defaultAppPredictionService));
}
private @NonNull String[] dropNonSystemPackages(@NonNull String[] pkgNames) {
@@ -21399,19 +21374,8 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public String getSystemCaptionsServicePackageName() {
- String flattenedSystemCaptionsServiceComponentName =
- mContext.getString(R.string.config_defaultSystemCaptionsService);
-
- if (TextUtils.isEmpty(flattenedSystemCaptionsServiceComponentName)) {
- return null;
- }
-
- ComponentName systemCaptionsServiceComponentName =
- ComponentName.unflattenFromString(flattenedSystemCaptionsServiceComponentName);
- if (systemCaptionsServiceComponentName == null) {
- return null;
- }
- return ensureSystemPackageName(systemCaptionsServiceComponentName.getPackageName());
+ return ensureSystemPackageName(
+ getPackageFromComponentString(R.string.config_defaultSystemCaptionsService));
}
@Override
@@ -21429,19 +21393,8 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public String getContentCaptureServicePackageName() {
- final String flattenedContentCaptureService =
- mContext.getString(R.string.config_defaultContentCaptureService);
-
- if (TextUtils.isEmpty(flattenedContentCaptureService)) {
- return null;
- }
-
- final ComponentName contentCaptureServiceComponentName =
- ComponentName.unflattenFromString(flattenedContentCaptureService);
- if (contentCaptureServiceComponentName == null) {
- return null;
- }
- return ensureSystemPackageName(contentCaptureServiceComponentName.getPackageName());
+ return ensureSystemPackageName(
+ getPackageFromComponentString(R.string.config_defaultContentCaptureService));
}
public String getOverlayConfigSignaturePackageName() {
@@ -21485,6 +21438,26 @@ public class PackageManagerService extends IPackageManager.Stub
}
@Nullable
+ private String getRecentsPackageName() {
+ return ensureSystemPackageName(
+ getPackageFromComponentString(R.string.config_recentsComponentName));
+
+ }
+
+ @Nullable
+ private String getPackageFromComponentString(@StringRes int stringResId) {
+ final String componentString = mContext.getString(stringResId);
+ if (TextUtils.isEmpty(componentString)) {
+ return null;
+ }
+ final ComponentName component = ComponentName.unflattenFromString(componentString);
+ if (component == null) {
+ return null;
+ }
+ return component.getPackageName();
+ }
+
+ @Nullable
private String ensureSystemPackageName(@Nullable String packageName) {
if (packageName == null) {
return null;
@@ -25092,6 +25065,8 @@ public class PackageManagerService extends IPackageManager.Stub
: new String[] {mRetailDemoPackage};
case PackageManagerInternal.PACKAGE_OVERLAY_CONFIG_SIGNATURE:
return filterOnlySystemPackages(getOverlayConfigSignaturePackageName());
+ case PackageManagerInternal.PACKAGE_RECENTS:
+ return filterOnlySystemPackages(mRecentsPackage);
default:
return ArrayUtils.emptyArray(String.class);
}
diff --git a/services/core/java/com/android/server/pm/permission/Permission.java b/services/core/java/com/android/server/pm/permission/Permission.java
index 687e96c3c9dd..995b59e97e91 100644
--- a/services/core/java/com/android/server/pm/permission/Permission.java
+++ b/services/core/java/com/android/server/pm/permission/Permission.java
@@ -331,6 +331,10 @@ public final class Permission {
return (mPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_FLAG_RETAIL_DEMO) != 0;
}
+ public boolean isRecents() {
+ return (mPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_FLAG_RECENTS) != 0;
+ }
+
public void transfer(@NonNull String oldPackageName, @NonNull String newPackageName) {
if (!oldPackageName.equals(mPermissionInfo.packageName)) {
return;
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 1b35d29f0d6b..311ba68b69ae 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -3616,6 +3616,13 @@ public class PermissionManagerService extends IPermissionManager.Stub {
// Special permission granted only to the OEM specified retail demo app
allowed = true;
}
+ if (!allowed && bp.isRecents()
+ && ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
+ PackageManagerInternal.PACKAGE_RECENTS, UserHandle.USER_SYSTEM),
+ pkg.getPackageName())) {
+ // Special permission for the recents app.
+ allowed = true;
+ }
return allowed;
}
@@ -4907,6 +4914,20 @@ public class PermissionManagerService extends IPermissionManager.Stub {
return true;
}
+ private void onPackageInstalledInternal(@NonNull AndroidPackage pkg,
+ @NonNull List<String> grantedPermissions,
+ @NonNull List<String> allowlistedRestrictedPermissions, int autoRevokePermissionsMode,
+ @NonNull int[] userIds) {
+ setAllowlistedRestrictedPermissionsInternal(pkg, allowlistedRestrictedPermissions,
+ FLAG_PERMISSION_WHITELIST_INSTALLER, userIds);
+ if (autoRevokePermissionsMode == AppOpsManager.MODE_ALLOWED
+ || autoRevokePermissionsMode == AppOpsManager.MODE_IGNORED) {
+ setAutoRevokeExemptedInternal(pkg,
+ autoRevokePermissionsMode == AppOpsManager.MODE_IGNORED, userIds);
+ }
+ grantRequestedRuntimePermissionsInternal(pkg, grantedPermissions, userIds);
+ }
+
private void onPackageRemovedInternal(@NonNull AndroidPackage pkg) {
removeAllPermissionsInternal(pkg);
}
@@ -5073,28 +5094,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
return PermissionManagerService.this.getAppOpPermissionPackagesInternal(permissionName);
}
@Override
- public void grantRequestedRuntimePermissions(@NonNull AndroidPackage pkg,
- @Nullable List<String> permissions, @NonNull int[] userIds) {
- Objects.requireNonNull(pkg, "pkg");
- Objects.requireNonNull(userIds, "userIds");
- grantRequestedRuntimePermissionsInternal(pkg, permissions, userIds);
- }
- @Override
- public void setAllowlistedRestrictedPermissions(@NonNull AndroidPackage pkg,
- @Nullable List<String> permissions, @PermissionWhitelistFlags int allowlistFlags,
- @NonNull int[] userIds) {
- Objects.requireNonNull(pkg, "pkg");
- Objects.requireNonNull(userIds, "userIds");
- setAllowlistedRestrictedPermissionsInternal(pkg, permissions, allowlistFlags, userIds);
- }
- @Override
- public void setAutoRevokeExempted(@NonNull AndroidPackage pkg, boolean exempted,
- @NonNull int[] userIds) {
- Objects.requireNonNull(pkg, "pkg");
- Objects.requireNonNull(userIds, "userIds");
- setAutoRevokeExemptedInternal(pkg, exempted, userIds);
- }
- @Override
public void updatePermissions(@NonNull String packageName, @Nullable AndroidPackage pkg) {
PermissionManagerService.this
.updatePermissions(packageName, pkg, mDefaultPermissionCallback);
@@ -5365,6 +5364,20 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
@Override
+ public void onPackageInstalled(@NonNull AndroidPackage pkg,
+ @NonNull List<String> grantedPermissions,
+ @NonNull List<String> allowlistedRestrictedPermissions,
+ int autoRevokePermissionsMode, @NonNull int[] userIds) {
+ Objects.requireNonNull(pkg, "pkg");
+ Objects.requireNonNull(grantedPermissions, "grantedPermissions");
+ Objects.requireNonNull(allowlistedRestrictedPermissions,
+ "allowlistedRestrictedPermissions");
+ Objects.requireNonNull(userIds, "userIds");
+ onPackageInstalledInternal(pkg, grantedPermissions, allowlistedRestrictedPermissions,
+ autoRevokePermissionsMode, userIds);
+ }
+
+ @Override
public void onPackageRemoved(@NonNull AndroidPackage pkg) {
Objects.requireNonNull(pkg);
onPackageRemovedInternal(pkg);
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index 1becbedc29fb..873bf87e5ab4 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -20,7 +20,6 @@ import android.annotation.AppIdInt;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
-import android.content.pm.PackageManager;
import android.content.pm.PermissionInfo;
import android.permission.PermissionManagerInternal;
@@ -190,42 +189,6 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager
@UserIdInt int userId);
/**
- * Grant the requested runtime permissions for a package, or an explicit subset of them.
- *
- * @param pkg the package
- * @param permissions the names of the subset of permissions to be granted, or {@code null} for
- * granting all the requested permissions
- * @param userIds the user IDs
- */
- //@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
- public abstract void grantRequestedRuntimePermissions(@NonNull AndroidPackage pkg,
- @Nullable List<String> permissions, @NonNull int[] userIds);
-
- /**
- * Set the allowlisted restricted permissions for a package, or an explicit subset of them.
- *
- * @param pkg the package
- * @param permissions the names of the subset of permissions to be allowlisted, or {@code null}
- * for allowlisting all the requested restricted permissions
- * @param userIds the user IDs
- */
- //@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
- public abstract void setAllowlistedRestrictedPermissions(
- @NonNull AndroidPackage pkg, @Nullable List<String> permissions,
- @PackageManager.PermissionWhitelistFlags int allowlistFlags, @NonNull int[] userIds);
-
- /**
- * Set whether a package is exempted from auto revoke.
- *
- * @param pkg the package
- * @param exempted whether the package is exempted from auto revoke
- * @param userIds the user IDs
- */
- //@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
- public abstract void setAutoRevokeExempted(@NonNull AndroidPackage pkg, boolean exempted,
- @NonNull int[] userIds);
-
- /**
* Update permissions when a package changed.
*
* <p><ol>
@@ -526,6 +489,21 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager
@Nullable AndroidPackage oldPkg);
/**
+ * Callback when a package has been installed for certain users.
+ *
+ * @param pkg the installed package
+ * @param grantedPermissions the permissions to be granted
+ * @param allowlistedRestrictedPermissions the restricted permissions to be allowlisted
+ * @param autoRevokePermissionsMode the auto revoke permissions mode for this package
+ * @param userIds the user IDs this package is installed for
+ */
+ //@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
+ public abstract void onPackageInstalled(@NonNull AndroidPackage pkg,
+ @NonNull List<String> grantedPermissions,
+ @NonNull List<String> allowlistedRestrictedPermissions,
+ int autoRevokePermissionsMode, @NonNull int[] userIds);
+
+ /**
* Callback when a package has been removed.
*
* @param pkg the removed package
diff --git a/services/core/java/com/android/server/powerstats/PowerStatsHALWrapper.java b/services/core/java/com/android/server/powerstats/PowerStatsHALWrapper.java
index 18646b9cc06c..88e5f69e02c4 100644
--- a/services/core/java/com/android/server/powerstats/PowerStatsHALWrapper.java
+++ b/services/core/java/com/android/server/powerstats/PowerStatsHALWrapper.java
@@ -38,11 +38,41 @@ public final class PowerStatsHALWrapper {
*/
public interface IPowerStatsHALWrapper {
/**
+ * Returns information related to all supported PowerEntity(s) for which state residency
+ * data is available.
+ *
+ * A PowerEntity is defined as a platform subsystem, peripheral, or power domain that
+ * impacts the total device power consumption.
+ *
+ * @return List of information on each PowerEntity.
+ */
+ android.hardware.power.stats.PowerEntityInfo[] getPowerEntityInfo();
+
+ /**
+ * Reports the accumulated state residency for each requested PowerEntity.
+ *
+ * Each PowerEntity may reside in one of multiple states. It may also transition from one
+ * state to another. StateResidency is defined as an accumulation of time that a
+ * PowerEntity resided in each of its possible states, the number of times that each state
+ * was entered, and a timestamp corresponding to the last time that state was entered.
+ *
+ * Data is accumulated starting at device boot.
+ *
+ * @param powerEntityIds List of IDs of PowerEntities for which data is requested. Passing
+ * an empty list will return state residency for all available
+ * PowerEntities. ID of each PowerEntity is contained in
+ * PowerEntityInfo.
+ *
+ * @return StateResidency since boot for each requested PowerEntity
+ */
+ android.hardware.power.stats.StateResidencyResult[] getStateResidency(int[] powerEntityIds);
+
+ /**
* Returns the energy consumer IDs for all available energy consumers (power models) on the
- * device. Examples of subsystems for which energy consumer results (power models)
- * may be available are GPS, display, wifi, etc. The default list of energy
- * consumers can be found in the PowerStats HAL definition (EnergyConsumerId.aidl).
- * The availability of energy consumer IDs is hardware dependent.
+ * device. Examples of subsystems for which energy consumer results (power models) may be
+ * available are GPS, display, wifi, etc. The default list of energy consumers can be
+ * found in the PowerStats HAL definition (EnergyConsumerId.aidl). The availability of
+ * energy consumer IDs is hardware dependent.
*
* @return List of EnergyConsumerIds all available energy consumers.
*/
@@ -50,14 +80,19 @@ public final class PowerStatsHALWrapper {
/**
* Returns the energy consumer result for all available energy consumers (power models).
- * Available consumers can be retrieved by calling getEnergyConsumerInfo(). The
- * subsystem corresponding to the energy consumer result is defined by the energy
- * consumer ID.
+ * Available consumers can be retrieved by calling getEnergyConsumerInfo(). The subsystem
+ * corresponding to the energy consumer result is defined by the energy consumer ID.
+ *
+ * @param energyConsumerIds Array of energy consumer IDs for which energy consumed is being
+ * requested. Energy consumers available on the device can be
+ * queried by calling getEnergyConsumerInfo(). Passing an empty
+ * array will return results for all energy consumers.
*
* @return List of EnergyConsumerResult objects containing energy consumer results for all
* available energy consumers (power models).
*/
- android.hardware.power.stats.EnergyConsumerResult[] getEnergyConsumed();
+ android.hardware.power.stats.EnergyConsumerResult[] getEnergyConsumed(
+ int[] energyConsumerIds);
/**
* Returns channel info for all available energy meters.
@@ -69,17 +104,21 @@ public final class PowerStatsHALWrapper {
/**
* Returns energy measurements for all available energy meters. Available channels can be
- * retrieved by calling getEnergyMeterInfo(). Energy measurements and channel info
- * can be linked through the channelId field.
+ * retrieved by calling getEnergyMeterInfo(). Energy measurements and channel info can be
+ * linked through the channelId field.
+ *
+ * @param channelIds Array of channel IDs for which energy measurements are being requested.
+ * Channel IDs available on the device can be queried by calling
+ * getEnergyMeterInfo(). Passing an empty array will return energy
+ * measurements for all channels.
*
* @return List of EnergyMeasurement objects containing energy measurements for all
* available energy meters.
*/
- android.hardware.power.stats.EnergyMeasurement[] readEnergyMeters();
+ android.hardware.power.stats.EnergyMeasurement[] readEnergyMeters(int[] channelIds);
/**
- * Returns boolean indicating if connection to power stats HAL was
- * established.
+ * Returns boolean indicating if connection to power stats HAL was established.
*
* @return true if connection to power stats HAL was correctly established.
*/
@@ -95,6 +134,38 @@ public final class PowerStatsHALWrapper {
private static Supplier<IPowerStats> sVintfPowerStats;
@Override
+ public android.hardware.power.stats.PowerEntityInfo[] getPowerEntityInfo() {
+ android.hardware.power.stats.PowerEntityInfo[] powerEntityInfoHAL = null;
+
+ if (sVintfPowerStats != null) {
+ try {
+ powerEntityInfoHAL = sVintfPowerStats.get().getPowerEntityInfo();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to get power entity info from PowerStats HAL");
+ }
+ }
+
+ return powerEntityInfoHAL;
+ }
+
+ @Override
+ public android.hardware.power.stats.StateResidencyResult[] getStateResidency(
+ int[] powerEntityIds) {
+ android.hardware.power.stats.StateResidencyResult[] stateResidencyResultHAL = null;
+
+ if (sVintfPowerStats != null) {
+ try {
+ stateResidencyResultHAL =
+ sVintfPowerStats.get().getStateResidency(powerEntityIds);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to get state residency from PowerStats HAL");
+ }
+ }
+
+ return stateResidencyResultHAL;
+ }
+
+ @Override
public int[] getEnergyConsumerInfo() {
int[] energyConsumerInfoHAL = null;
@@ -110,13 +181,14 @@ public final class PowerStatsHALWrapper {
}
@Override
- public android.hardware.power.stats.EnergyConsumerResult[] getEnergyConsumed() {
+ public android.hardware.power.stats.EnergyConsumerResult[] getEnergyConsumed(
+ int[] energyConsumerIds) {
android.hardware.power.stats.EnergyConsumerResult[] energyConsumedHAL = null;
if (sVintfPowerStats != null) {
try {
energyConsumedHAL =
- sVintfPowerStats.get().getEnergyConsumed(new int[0]);
+ sVintfPowerStats.get().getEnergyConsumed(energyConsumerIds);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to get energy consumer results from PowerStats HAL");
}
@@ -141,13 +213,13 @@ public final class PowerStatsHALWrapper {
}
@Override
- public android.hardware.power.stats.EnergyMeasurement[] readEnergyMeters() {
+ public android.hardware.power.stats.EnergyMeasurement[] readEnergyMeters(int[] channelIds) {
android.hardware.power.stats.EnergyMeasurement[] energyMeasurementHAL = null;
if (sVintfPowerStats != null) {
try {
energyMeasurementHAL =
- sVintfPowerStats.get().readEnergyMeters(new int[0]);
+ sVintfPowerStats.get().readEnergyMeters(channelIds);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to get energy measurements from PowerStats HAL");
}
diff --git a/services/core/java/com/android/server/powerstats/PowerStatsLogger.java b/services/core/java/com/android/server/powerstats/PowerStatsLogger.java
index f5131c4b371d..409cd826b6bc 100644
--- a/services/core/java/com/android/server/powerstats/PowerStatsLogger.java
+++ b/services/core/java/com/android/server/powerstats/PowerStatsLogger.java
@@ -61,14 +61,15 @@ public final class PowerStatsLogger extends Handler {
if (DEBUG) Slog.d(TAG, "Logging to data storage");
// Log power meter data.
- EnergyMeasurement[] energyMeasurements = mPowerStatsHALWrapper.readEnergyMeters();
+ EnergyMeasurement[] energyMeasurements =
+ mPowerStatsHALWrapper.readEnergyMeters(new int[0]);
mPowerStatsMeterStorage.write(
EnergyMeasurementUtils.getProtoBytes(energyMeasurements));
if (DEBUG) EnergyMeasurementUtils.print(energyMeasurements);
// Log power model data.
EnergyConsumerResult[] energyConsumerResults =
- mPowerStatsHALWrapper.getEnergyConsumed();
+ mPowerStatsHALWrapper.getEnergyConsumed(new int[0]);
mPowerStatsModelStorage.write(
EnergyConsumerResultUtils.getProtoBytes(energyConsumerResults));
if (DEBUG) EnergyConsumerResultUtils.print(energyConsumerResults);
diff --git a/services/core/java/com/android/server/powerstats/PowerStatsService.java b/services/core/java/com/android/server/powerstats/PowerStatsService.java
index bf3919e7344f..1150d4bbe770 100644
--- a/services/core/java/com/android/server/powerstats/PowerStatsService.java
+++ b/services/core/java/com/android/server/powerstats/PowerStatsService.java
@@ -19,6 +19,7 @@ package com.android.server.powerstats;
import android.annotation.Nullable;
import android.content.Context;
import android.hardware.power.stats.ChannelInfo;
+import android.hardware.power.stats.PowerEntityInfo;
import android.os.Binder;
import android.os.Environment;
import android.os.UserHandle;
@@ -31,6 +32,7 @@ import com.android.server.powerstats.PowerStatsHALWrapper.IPowerStatsHALWrapper;
import com.android.server.powerstats.PowerStatsHALWrapper.PowerStatsHALWrapperImpl;
import com.android.server.powerstats.ProtoStreamUtils.ChannelInfoUtils;
import com.android.server.powerstats.ProtoStreamUtils.EnergyConsumerIdUtils;
+import com.android.server.powerstats.ProtoStreamUtils.PowerEntityInfoUtils;
import java.io.File;
import java.io.FileDescriptor;
@@ -110,6 +112,10 @@ public class PowerStatsService extends SystemService {
mPowerStatsLogger.writeMeterDataToFile(fd);
}
} else if (args.length == 0) {
+ pw.println("PowerStatsService dumpsys: available PowerEntityInfos");
+ PowerEntityInfo[] powerEntityInfo = mPowerStatsHALWrapper.getPowerEntityInfo();
+ PowerEntityInfoUtils.dumpsys(powerEntityInfo, pw);
+
pw.println("PowerStatsService dumpsys: available ChannelInfos");
ChannelInfo[] channelInfo = mPowerStatsHALWrapper.getEnergyMeterInfo();
ChannelInfoUtils.dumpsys(channelInfo, pw);
diff --git a/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java b/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java
index 43afeed8b925..5a4256ac0264 100644
--- a/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java
+++ b/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java
@@ -19,6 +19,8 @@ package com.android.server.powerstats;
import android.hardware.power.stats.ChannelInfo;
import android.hardware.power.stats.EnergyConsumerResult;
import android.hardware.power.stats.EnergyMeasurement;
+import android.hardware.power.stats.PowerEntityInfo;
+import android.hardware.power.stats.StateResidencyResult;
import android.util.Slog;
import android.util.proto.ProtoInputStream;
import android.util.proto.ProtoOutputStream;
@@ -42,6 +44,48 @@ import java.util.List;
public class ProtoStreamUtils {
private static final String TAG = ProtoStreamUtils.class.getSimpleName();
+ static class PowerEntityInfoUtils {
+ public static void print(PowerEntityInfo[] powerEntityInfo) {
+ for (int i = 0; i < powerEntityInfo.length; i++) {
+ Slog.d(TAG, "PowerEntityId: " + powerEntityInfo[i].powerEntityId
+ + ", PowerEntityName: " + powerEntityInfo[i].powerEntityName);
+ for (int j = 0; j < powerEntityInfo[i].states.length; j++) {
+ Slog.d(TAG, " StateId: " + powerEntityInfo[i].states[j].stateId
+ + ", StateName: " + powerEntityInfo[i].states[j].stateName);
+ }
+ }
+ }
+
+ public static void dumpsys(PowerEntityInfo[] powerEntityInfo, PrintWriter pw) {
+ for (int i = 0; i < powerEntityInfo.length; i++) {
+ pw.println("PowerEntityId: " + powerEntityInfo[i].powerEntityId
+ + ", PowerEntityName: " + powerEntityInfo[i].powerEntityName);
+ for (int j = 0; j < powerEntityInfo[i].states.length; j++) {
+ pw.println(" StateId: " + powerEntityInfo[i].states[j].stateId
+ + ", StateName: " + powerEntityInfo[i].states[j].stateName);
+ }
+ }
+ }
+ }
+
+ static class StateResidencyResultUtils {
+ public static void print(StateResidencyResult[] stateResidencyResult) {
+ for (int i = 0; i < stateResidencyResult.length; i++) {
+ Slog.d(TAG, "PowerEntityId: " + stateResidencyResult[i].powerEntityId);
+ for (int j = 0; j < stateResidencyResult[i].stateResidencyData.length; j++) {
+ Slog.d(TAG, " StateId: "
+ + stateResidencyResult[i].stateResidencyData[j].stateId
+ + ", TotalTimeInStateMs: "
+ + stateResidencyResult[i].stateResidencyData[j].totalTimeInStateMs
+ + ", TotalStateEntryCount: "
+ + stateResidencyResult[i].stateResidencyData[j].totalStateEntryCount
+ + ", LastEntryTimestampMs: "
+ + stateResidencyResult[i].stateResidencyData[j].lastEntryTimestampMs);
+ }
+ }
+ }
+ }
+
static class ChannelInfoUtils {
public static void packProtoMessage(ChannelInfo[] channelInfo, ProtoOutputStream pos) {
long token;
@@ -57,15 +101,15 @@ public class ProtoStreamUtils {
public static void print(ChannelInfo[] channelInfo) {
for (int i = 0; i < channelInfo.length; i++) {
- Slog.d(TAG, "ChannelId = " + channelInfo[i].channelId
- + ", ChannelName = " + channelInfo[i].channelName);
+ Slog.d(TAG, "ChannelId: " + channelInfo[i].channelId
+ + ", ChannelName: " + channelInfo[i].channelName);
}
}
public static void dumpsys(ChannelInfo[] channelInfo, PrintWriter pw) {
for (int i = 0; i < channelInfo.length; i++) {
- pw.println("ChannelId = " + channelInfo[i].channelId
- + ", ChannelName = " + channelInfo[i].channelName);
+ pw.println("ChannelId: " + channelInfo[i].channelId
+ + ", ChannelName: " + channelInfo[i].channelName);
}
}
}
@@ -157,9 +201,9 @@ public class ProtoStreamUtils {
public static void print(EnergyMeasurement[] energyMeasurement) {
for (int i = 0; i < energyMeasurement.length; i++) {
- Slog.d(TAG, "ChannelId = " + energyMeasurement[i].channelId
- + ", Timestamp (ms) = " + energyMeasurement[i].timestampMs
- + ", Energy (uWs) = " + energyMeasurement[i].energyUWs);
+ Slog.d(TAG, "ChannelId: " + energyMeasurement[i].channelId
+ + ", Timestamp (ms): " + energyMeasurement[i].timestampMs
+ + ", Energy (uWs): " + energyMeasurement[i].energyUWs);
}
}
}
@@ -177,13 +221,13 @@ public class ProtoStreamUtils {
public static void print(int[] energyConsumerId) {
for (int i = 0; i < energyConsumerId.length; i++) {
- Slog.d(TAG, "EnergyConsumerId = " + energyConsumerId[i]);
+ Slog.d(TAG, "EnergyConsumerId: " + energyConsumerId[i]);
}
}
public static void dumpsys(int[] energyConsumerId, PrintWriter pw) {
for (int i = 0; i < energyConsumerId.length; i++) {
- pw.println("EnergyConsumerId = " + energyConsumerId[i]);
+ pw.println("EnergyConsumerId: " + energyConsumerId[i]);
}
}
}
@@ -278,9 +322,9 @@ public class ProtoStreamUtils {
public static void print(EnergyConsumerResult[] energyConsumerResult) {
for (int i = 0; i < energyConsumerResult.length; i++) {
- Slog.d(TAG, "EnergyConsumerId = " + energyConsumerResult[i].energyConsumerId
- + ", Timestamp (ms) = " + energyConsumerResult[i].timestampMs
- + ", Energy (uWs) = " + energyConsumerResult[i].energyUWs);
+ Slog.d(TAG, "EnergyConsumerId: " + energyConsumerResult[i].energyConsumerId
+ + ", Timestamp (ms): " + energyConsumerResult[i].timestampMs
+ + ", Energy (uWs): " + energyConsumerResult[i].energyUWs);
}
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
index 8ad2958f9a76..48e030050b07 100644
--- a/services/core/java/com/android/server/wm/DisplayArea.java
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -382,6 +382,13 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> {
@Nullable
@Override
+ <R> R getItemFromDisplayAreas(Function<DisplayArea, R> callback) {
+ final R item = super.getItemFromDisplayAreas(callback);
+ return item != null ? item : callback.apply(this);
+ }
+
+ @Nullable
+ @Override
<R> R getItemFromTaskDisplayAreas(Function<TaskDisplayArea, R> callback,
boolean traverseTopToBottom) {
// Only DisplayArea of Type.ANY may contain TaskDisplayArea as children.
diff --git a/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java b/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
index 43b9a218d072..c475da354dda 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
@@ -16,7 +16,10 @@
package com.android.server.wm;
+import static android.window.DisplayAreaOrganizer.FEATURE_RUNTIME_TASK_CONTAINER_FIRST;
+
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
+import static com.android.server.wm.DisplayArea.Type.ANY;
import android.content.pm.ParceledListSlice;
import android.os.Binder;
@@ -26,6 +29,7 @@ import android.view.SurfaceControl;
import android.window.DisplayAreaAppearedInfo;
import android.window.IDisplayAreaOrganizer;
import android.window.IDisplayAreaOrganizerController;
+import android.window.WindowContainerToken;
import com.android.internal.protolog.common.ProtoLog;
@@ -36,6 +40,12 @@ import java.util.List;
public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerController.Stub {
private static final String TAG = "DisplayAreaOrganizerController";
+ /**
+ * Next available feature id for a runtime task display area.
+ * @see #createTaskDisplayArea(IDisplayAreaOrganizer organizer, int, int, String)
+ */
+ private int mNextTaskDisplayAreaFeatureId = FEATURE_RUNTIME_TASK_CONTAINER_FIRST;
+
final ActivityTaskManagerService mService;
private final WindowManagerGlobalLock mGlobalLock;
private final HashMap<Integer, IDisplayAreaOrganizer> mOrganizersByFeatureIds = new HashMap();
@@ -92,10 +102,8 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl
final List<DisplayAreaAppearedInfo> displayAreaInfos = new ArrayList<>();
mService.mRootWindowContainer.forAllDisplayAreas((da) -> {
if (da.mFeatureId != feature) return;
- da.setOrganizer(organizer, true /* skipDisplayAreaAppeared */);
- displayAreaInfos.add(new DisplayAreaAppearedInfo(da.getDisplayAreaInfo(),
- new SurfaceControl(da.getSurfaceControl(),
- "DisplayAreaOrganizerController.registerOrganizer")));
+ displayAreaInfos.add(organizeDisplayArea(organizer, da,
+ "DisplayAreaOrganizerController.registerOrganizer"));
});
mOrganizersByFeatureIds.put(feature, organizer);
@@ -124,6 +132,77 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl
}
}
+ @Override
+ public DisplayAreaAppearedInfo createTaskDisplayArea(IDisplayAreaOrganizer organizer,
+ int displayId, int rootFeatureId, String name) {
+ enforceTaskPermission("createTaskDisplayArea()");
+ final long uid = Binder.getCallingUid();
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Create TaskDisplayArea uid=%d", uid);
+
+ final DisplayContent display =
+ mService.mRootWindowContainer.getDisplayContent(displayId);
+ if (display == null) {
+ throw new IllegalArgumentException("createTaskDisplayArea unknown displayId="
+ + displayId);
+ }
+
+ final DisplayArea root = display.getItemFromDisplayAreas(da ->
+ da.asRootDisplayArea() != null && da.mFeatureId == rootFeatureId
+ ? da
+ : null);
+ if (root == null) {
+ throw new IllegalArgumentException("Can't find RootDisplayArea with featureId="
+ + rootFeatureId);
+ }
+
+ final int taskDisplayAreaFeatureId = mNextTaskDisplayAreaFeatureId++;
+ final DeathRecipient dr = new DeathRecipient(organizer, taskDisplayAreaFeatureId);
+ try {
+ organizer.asBinder().linkToDeath(dr, 0);
+ } catch (RemoteException e) {
+ // Oh well...
+ }
+
+ final TaskDisplayArea tda = createTaskDisplayArea(root.asRootDisplayArea(), name,
+ taskDisplayAreaFeatureId);
+ return organizeDisplayArea(organizer, tda,
+ "DisplayAreaOrganizerController.createTaskDisplayArea");
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ @Override
+ public void deleteTaskDisplayArea(WindowContainerToken token) {
+ enforceTaskPermission("deleteTaskDisplayArea()");
+ final long uid = Binder.getCallingUid();
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Delete TaskDisplayArea uid=%d", uid);
+
+ final WindowContainer wc = WindowContainer.fromBinder(token.asBinder());
+ if (wc == null || wc.asTaskDisplayArea() == null) {
+ throw new IllegalArgumentException("Can't resolve TaskDisplayArea from token");
+ }
+ final TaskDisplayArea taskDisplayArea = wc.asTaskDisplayArea();
+ if (!taskDisplayArea.mCreatedByOrganizer) {
+ throw new IllegalArgumentException(
+ "Attempt to delete TaskDisplayArea not created by organizer "
+ + "TaskDisplayArea=" + taskDisplayArea);
+ }
+
+ deleteTaskDisplayArea(taskDisplayArea);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
void onDisplayAreaAppeared(IDisplayAreaOrganizer organizer, DisplayArea da) {
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "DisplayArea appeared name=%s", da.getName());
try {
@@ -157,8 +236,71 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl
IBinder organizerBinder = organizer.asBinder();
mService.mRootWindowContainer.forAllDisplayAreas((da) -> {
if (da.mOrganizer != null && da.mOrganizer.asBinder().equals(organizerBinder)) {
- da.setOrganizer(null);
+ if (da.isTaskDisplayArea() && da.asTaskDisplayArea().mCreatedByOrganizer) {
+ // Delete the organizer created TDA when unregister.
+ deleteTaskDisplayArea(da.asTaskDisplayArea());
+ } else {
+ da.setOrganizer(null);
+ }
+ }
+ });
+ }
+
+ private DisplayAreaAppearedInfo organizeDisplayArea(IDisplayAreaOrganizer organizer,
+ DisplayArea displayArea, String callsite) {
+ displayArea.setOrganizer(organizer, true /* skipDisplayAreaAppeared */);
+ return new DisplayAreaAppearedInfo(displayArea.getDisplayAreaInfo(),
+ new SurfaceControl(displayArea.getSurfaceControl(), callsite));
+ }
+
+ private TaskDisplayArea createTaskDisplayArea(RootDisplayArea root, String name,
+ int taskDisplayAreaFeatureId) {
+ final TaskDisplayArea taskDisplayArea = new TaskDisplayArea(root.mDisplayContent,
+ root.mWmService, name, taskDisplayAreaFeatureId, true /* createdByOrganizer */);
+
+ // Find the top most DA that can contain Task (either a TDA or a DisplayAreaGroup).
+ final DisplayArea topTaskContainer = root.getItemFromDisplayAreas(da -> {
+ if (da.mType != ANY) {
+ return null;
+ }
+
+ final RootDisplayArea rootDA = da.getRootDisplayArea();
+ if (rootDA == root || rootDA == da) {
+ // Either it is the top TDA below the root or it is a DisplayAreaGroup.
+ return da;
}
+ return null;
});
+ if (topTaskContainer == null) {
+ throw new IllegalStateException("Root must either contain TDA or DAG root=" + root);
+ }
+
+ // Insert the TaskDisplayArea as the top Task container.
+ final WindowContainer parent = topTaskContainer.getParent();
+ final int index = parent.mChildren.indexOf(topTaskContainer) + 1;
+ parent.addChild(taskDisplayArea, index);
+
+ return taskDisplayArea;
+ }
+
+ private void deleteTaskDisplayArea(TaskDisplayArea taskDisplayArea) {
+ taskDisplayArea.setOrganizer(null);
+ mService.mRootWindowContainer.mTaskSupervisor.beginDeferResume();
+
+ // TaskDisplayArea#remove() move the stacks to the default TaskDisplayArea.
+ Task lastReparentedStack;
+ try {
+ lastReparentedStack = taskDisplayArea.remove();
+ } finally {
+ mService.mRootWindowContainer.mTaskSupervisor.endDeferResume();
+ }
+
+ taskDisplayArea.removeImmediately();
+
+ // Only update focus/visibility for the last one because there may be many stacks are
+ // reparented and the intermediate states are unnecessary.
+ if (lastReparentedStack != null) {
+ lastReparentedStack.postReparent();
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java b/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
index 80ec722bc274..6a420874b924 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
@@ -172,10 +172,16 @@ class DisplayAreaPolicyBuilder {
throw new IllegalStateException("Root must be set for the display area policy.");
}
+ final Set<Integer> rootIdSet = new ArraySet<>();
+ rootIdSet.add(mRootHierarchyBuilder.mRoot.mFeatureId);
boolean containsImeContainer = mRootHierarchyBuilder.mImeContainer != null;
boolean containsDefaultTda = containsDefaultTaskDisplayArea(mRootHierarchyBuilder);
for (int i = 0; i < mDisplayAreaGroupHierarchyBuilders.size(); i++) {
HierarchyBuilder hierarchyBuilder = mDisplayAreaGroupHierarchyBuilders.get(i);
+ if (!rootIdSet.add(hierarchyBuilder.mRoot.mFeatureId)) {
+ throw new IllegalStateException("There should not be two RootDisplayAreas with id "
+ + hierarchyBuilder.mRoot.mFeatureId);
+ }
if (hierarchyBuilder.mTaskDisplayAreas.isEmpty()) {
throw new IllegalStateException(
"DisplayAreaGroup must contain at least one TaskDisplayArea.");
diff --git a/services/core/java/com/android/server/wm/RootDisplayArea.java b/services/core/java/com/android/server/wm/RootDisplayArea.java
index 1e5d045e8680..da04f438a496 100644
--- a/services/core/java/com/android/server/wm/RootDisplayArea.java
+++ b/services/core/java/com/android/server/wm/RootDisplayArea.java
@@ -57,6 +57,11 @@ class RootDisplayArea extends DisplayArea<DisplayArea> {
return this;
}
+ @Override
+ RootDisplayArea asRootDisplayArea() {
+ return this;
+ }
+
/** Whether the orientation (based on dimensions) of this root is different from the Display. */
boolean isOrientationDifferentFromDisplay() {
return false;
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index c02e7ad5b7c6..81b8200aa2b4 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -157,12 +157,24 @@ final class TaskDisplayArea extends DisplayArea<Task> {
*/
private int mLastLeafTaskToFrontId;
+ /**
+ * Whether this TaskDisplayArea was created by a {@link android.window.DisplayAreaOrganizer}.
+ * If {@code true}, this will be removed when the organizer is unregistered.
+ */
+ final boolean mCreatedByOrganizer;
+
TaskDisplayArea(DisplayContent displayContent, WindowManagerService service, String name,
int displayAreaFeature) {
+ this(displayContent, service, name, displayAreaFeature, false /* createdByOrganizer */);
+ }
+
+ TaskDisplayArea(DisplayContent displayContent, WindowManagerService service, String name,
+ int displayAreaFeature, boolean createdByOrganizer) {
super(service, Type.ANY, name, displayAreaFeature);
mDisplayContent = displayContent;
mRootWindowContainer = service.mRoot;
mAtmService = service.mAtmService;
+ mCreatedByOrganizer = createdByOrganizer;
}
/**
@@ -1914,6 +1926,11 @@ final class TaskDisplayArea extends DisplayArea<Task> {
}
@Override
+ TaskDisplayArea asTaskDisplayArea() {
+ return this;
+ }
+
+ @Override
void dump(PrintWriter pw, String prefix, boolean dumpAll) {
pw.println(prefix + "TaskDisplayArea " + getName());
final String doublePrefix = prefix + " ";
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 4574be70674f..06449c69f1be 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -1814,7 +1814,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
/**
* For all {@link TaskDisplayArea} at or below this container call the callback.
* @param callback Applies on each {@link TaskDisplayArea} found and stops the search if it
- * returns {@code true}.
+ * returns {@code true}.
* @param traverseTopToBottom If {@code true}, traverses the hierarchy from top-to-bottom in
* terms of z-order, else from bottom-to-top.
* @return {@code true} if the search ended before we reached the end of the hierarchy due to
@@ -1837,7 +1837,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
* For all {@link TaskDisplayArea} at or below this container call the callback. Traverses from
* top to bottom in terms of z-order.
* @param callback Applies on each {@link TaskDisplayArea} found and stops the search if it
- * returns {@code true}.
+ * returns {@code true}.
* @return {@code true} if the search ended before we reached the end of the hierarchy due to
* callback returning {@code true}.
*/
@@ -1873,7 +1873,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
* Performs a reduction on all {@link TaskDisplayArea} at or below this container, using the
* provided initial value and an accumulation function, and returns the reduced value.
* @param accumulator Applies on each {@link TaskDisplayArea} found with the accumulative result
- * from the previous call.
+ * from the previous call.
* @param initValue The initial value to pass to the accumulating function with the first
* {@link TaskDisplayArea}.
* @param traverseTopToBottom If {@code true}, traverses the hierarchy from top-to-bottom in
@@ -1899,7 +1899,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
* provided initial value and an accumulation function, and returns the reduced value. Traverses
* from top to bottom in terms of z-order.
* @param accumulator Applies on each {@link TaskDisplayArea} found with the accumulative result
- * from the previous call.
+ * from the previous call.
* @param initValue The initial value to pass to the accumulating function with the first
* {@link TaskDisplayArea}.
* @return the accumulative result.
@@ -1912,9 +1912,29 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
/**
* Finds the first non {@code null} return value from calling the callback on all
+ * {@link DisplayArea} at or below this container. Traverses from top to bottom in terms of
+ * z-order.
+ * @param callback Applies on each {@link DisplayArea} found and stops the search if it
+ * returns non {@code null}.
+ * @return the first returned object that is not {@code null}. Returns {@code null} if not
+ * found.
+ */
+ @Nullable
+ <R> R getItemFromDisplayAreas(Function<DisplayArea, R> callback) {
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ R result = (R) mChildren.get(i).getItemFromDisplayAreas(callback);
+ if (result != null) {
+ return result;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Finds the first non {@code null} return value from calling the callback on all
* {@link TaskDisplayArea} at or below this container.
* @param callback Applies on each {@link TaskDisplayArea} found and stops the search if it
- * returns non {@code null}.
+ * returns non {@code null}.
* @param traverseTopToBottom If {@code true}, traverses the hierarchy from top-to-bottom in
* terms of z-order, else from bottom-to-top.
* @return the first returned object that is not {@code null}. Returns {@code null} if not
@@ -1941,7 +1961,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
* {@link TaskDisplayArea} at or below this container. Traverses from top to bottom in terms of
* z-order.
* @param callback Applies on each {@link TaskDisplayArea} found and stops the search if it
- * returns non {@code null}.
+ * returns non {@code null}.
* @return the first returned object that is not {@code null}. Returns {@code null} if not
* found.
*/
@@ -2884,6 +2904,16 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
return null;
}
+ /** Cheap way of doing cast and instanceof. */
+ RootDisplayArea asRootDisplayArea() {
+ return null;
+ }
+
+ /** Cheap way of doing cast and instanceof. */
+ TaskDisplayArea asTaskDisplayArea() {
+ return null;
+ }
+
/**
* @return {@code true} if window container is manage by a
* {@link android.window.WindowOrganizer}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index a6466821ff38..78d4f2fcc563 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -3192,6 +3192,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
}
+ private void checkAllUsersAreAffiliatedWithDevice() {
+ Preconditions.checkCallAuthorization(areAllUsersAffiliatedWithDeviceLocked(),
+ "operation not allowed when device has unaffiliated users");
+ }
+
@Override
public boolean isAdminActive(ComponentName adminReceiver, int userHandle) {
if (!mHasFeature) {
@@ -7034,7 +7039,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
// next boot? Might not be needed given that this still requires user consent.
final CallerIdentity caller = getCallerIdentity(who);
Preconditions.checkCallAuthorization(isDeviceOwner(caller));
- Preconditions.checkCallAuthorization(areAllUsersAffiliatedWithDeviceLocked());
+ checkAllUsersAreAffiliatedWithDevice();
if (mBugreportCollectionManager.requestBugreport()) {
DevicePolicyEventLogger
@@ -8643,6 +8648,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
pw.println(policy.mUserControlDisabledPackages);
pw.print("mAppsSuspended="); pw.println(policy.mAppsSuspended);
pw.print("mUserSetupComplete="); pw.println(policy.mUserSetupComplete);
+ pw.print("mAffiliationIds="); pw.println(policy.mAffiliationIds);
pw.decreaseIndent();
}
}
@@ -12925,13 +12931,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
});
}
- private boolean canStartSecurityLogging() {
- synchronized (getLockObject()) {
- return isOrganizationOwnedDeviceWithManagedProfile()
- || areAllUsersAffiliatedWithDeviceLocked();
- }
- }
-
private @UserIdInt int getSecurityLoggingEnabledUser() {
synchronized (getLockObject()) {
if (mOwners.hasDeviceOwner()) {
@@ -13651,7 +13650,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
final CallerIdentity caller = getCallerIdentity(admin, packageName);
Preconditions.checkCallAuthorization((caller.hasAdminComponent() && isDeviceOwner(caller))
|| (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_NETWORK_LOGGING)));
- Preconditions.checkCallAuthorization(areAllUsersAffiliatedWithDeviceLocked());
+ checkAllUsersAreAffiliatedWithDevice();
synchronized (getLockObject()) {
if (mNetworkLogger == null || !isNetworkLoggingEnabledInternalLocked()) {
diff --git a/services/tests/mockingservicestests/Android.bp b/services/tests/mockingservicestests/Android.bp
index a2e6698963a4..8fc5c085999e 100644
--- a/services/tests/mockingservicestests/Android.bp
+++ b/services/tests/mockingservicestests/Android.bp
@@ -20,6 +20,7 @@ android_test {
static_libs: [
"services.core",
"services.net",
+ "services.usage",
"service-jobscheduler",
"service-permission.impl",
"service-blobstore",
diff --git a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
index ebd4a4c5378f..9c8f733730a7 100644
--- a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
@@ -174,8 +174,6 @@ public class RescuePartyTest {
doReturn(CURRENT_NETWORK_TIME_MILLIS).when(() -> RescueParty.getElapsedRealtime());
- SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL,
- Integer.toString(RescueParty.LEVEL_NONE));
SystemProperties.set(RescueParty.PROP_RESCUE_BOOT_COUNT, Integer.toString(0));
SystemProperties.set(RescueParty.PROP_ENABLE_RESCUE, Boolean.toString(true));
SystemProperties.set(PROP_DEVICE_CONFIG_DISABLE_FLAG, Boolean.toString(false));
@@ -193,12 +191,10 @@ public class RescuePartyTest {
mMonitorCallbackCaptor.capture()));
HashMap<String, Integer> verifiedTimesMap = new HashMap<String, Integer>();
- noteBoot();
+ noteBoot(1);
verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS, /*resetNamespaces=*/ null,
verifiedTimesMap);
- assertEquals(RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS,
- SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
// Record DeviceConfig accesses
RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);
@@ -208,24 +204,19 @@ public class RescuePartyTest {
final String[] expectedAllResetNamespaces = new String[]{NAMESPACE1, NAMESPACE2};
- noteBoot();
+ noteBoot(2);
verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_CHANGES, expectedAllResetNamespaces,
verifiedTimesMap);
- assertEquals(RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES,
- SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
- noteBoot();
+ noteBoot(3);
verifySettingsResets(Settings.RESET_MODE_TRUSTED_DEFAULTS, expectedAllResetNamespaces,
verifiedTimesMap);
- assertEquals(RescueParty.LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS,
- SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
- noteBoot();
+ noteBoot(4);
- assertEquals(LEVEL_FACTORY_RESET,
- SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
+ assertTrue(RescueParty.isAttemptingFactoryReset());
}
@Test
@@ -364,24 +355,12 @@ public class RescuePartyTest {
@Test
public void testIsAttemptingFactoryReset() {
for (int i = 0; i < LEVEL_FACTORY_RESET; i++) {
- noteBoot();
+ noteBoot(i + 1);
}
assertTrue(RescueParty.isAttemptingFactoryReset());
}
@Test
- public void testOnSettingsProviderPublishedExecutesRescueLevels() {
- SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL, Integer.toString(1));
-
- RescueParty.onSettingsProviderPublished(mMockContext);
-
- verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS, /*resetNamespaces=*/ null,
- /*configResetVerifiedTimesMap=*/ null);
- assertEquals(RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS,
- SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
- }
-
- @Test
public void testNativeRescuePartyResets() {
doReturn(true).when(() -> SettingsToPropertiesMapper.isNativeFlagsResetPerformed());
doReturn(FAKE_RESET_NATIVE_NAMESPACES).when(
@@ -425,7 +404,7 @@ public class RescuePartyTest {
SystemProperties.set(PROP_DISABLE_FACTORY_RESET_FLAG, Boolean.toString(true));
for (int i = 0; i < LEVEL_FACTORY_RESET; i++) {
- noteBoot();
+ noteBoot(i + 1);
}
assertFalse(RescueParty.isAttemptingFactoryReset());
@@ -463,29 +442,12 @@ public class RescuePartyTest {
public void testBootLoopLevels() {
RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);
- /*
- Ensure that the returned user impact corresponds with the user impact of the next available
- rescue level, not the current one.
- */
- SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL, Integer.toString(
- RescueParty.LEVEL_NONE));
- assertEquals(observer.onBootLoop(), PackageHealthObserverImpact.USER_IMPACT_LOW);
-
- SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL, Integer.toString(
- RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS));
- assertEquals(observer.onBootLoop(), PackageHealthObserverImpact.USER_IMPACT_LOW);
-
- SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL, Integer.toString(
- RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES));
- assertEquals(observer.onBootLoop(), PackageHealthObserverImpact.USER_IMPACT_HIGH);
-
- SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL, Integer.toString(
- RescueParty.LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS));
- assertEquals(observer.onBootLoop(), PackageHealthObserverImpact.USER_IMPACT_HIGH);
-
- SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL, Integer.toString(
- LEVEL_FACTORY_RESET));
- assertEquals(observer.onBootLoop(), PackageHealthObserverImpact.USER_IMPACT_HIGH);
+ assertEquals(observer.onBootLoop(0), PackageHealthObserverImpact.USER_IMPACT_NONE);
+ assertEquals(observer.onBootLoop(1), PackageHealthObserverImpact.USER_IMPACT_LOW);
+ assertEquals(observer.onBootLoop(2), PackageHealthObserverImpact.USER_IMPACT_LOW);
+ assertEquals(observer.onBootLoop(3), PackageHealthObserverImpact.USER_IMPACT_HIGH);
+ assertEquals(observer.onBootLoop(4), PackageHealthObserverImpact.USER_IMPACT_HIGH);
+ assertEquals(observer.onBootLoop(5), PackageHealthObserverImpact.USER_IMPACT_HIGH);
}
private void verifySettingsResets(int resetMode, String[] resetNamespaces,
@@ -513,8 +475,8 @@ public class RescuePartyTest {
}
}
- private void noteBoot() {
- RescuePartyObserver.getInstance(mMockContext).executeBootLoopMitigation();
+ private void noteBoot(int mitigationCount) {
+ RescuePartyObserver.getInstance(mMockContext).executeBootLoopMitigation(mitigationCount);
}
private void notePersistentAppCrash(int mitigationCount) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/usage/UsageStatsServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/usage/UsageStatsServiceTest.java
new file mode 100644
index 000000000000..c9fcd0233bef
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/usage/UsageStatsServiceTest.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.usage;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
+
+import android.app.ActivityManager;
+import android.app.IActivityManager;
+import android.app.usage.UsageEvents;
+import android.app.usage.UsageStatsManagerInternal;
+import android.content.Context;
+import android.os.RemoteException;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.LocalServices;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class UsageStatsServiceTest {
+ private static final long TIMEOUT = 5000;
+
+ private UsageStatsService mService;
+
+ private MockitoSession mMockingSession;
+ @Mock
+ private Context mContext;
+
+ private static class TestInjector extends UsageStatsService.Injector {
+ AppStandbyInternal getAppStandbyController(Context context) {
+ return mock(AppStandbyInternal.class);
+ }
+ }
+
+ @Before
+ public void setUp() {
+ mMockingSession = mockitoSession()
+ .initMocks(this)
+ .strictness(Strictness.LENIENT)
+ .startMocking();
+ IActivityManager activityManager = ActivityManager.getService();
+ spyOn(activityManager);
+ try {
+ doNothing().when(activityManager).registerUidObserver(any(), anyInt(), anyInt(), any());
+ } catch (RemoteException e) {
+ fail("registerUidObserver threw exception: " + e.getMessage());
+ }
+ mService = new UsageStatsService(mContext, new TestInjector());
+ spyOn(mService);
+ doNothing().when(mService).publishBinderServices();
+ mService.onStart();
+ }
+
+ @Test
+ public void testUsageEventListener() throws Exception {
+ TestUsageEventListener listener = new TestUsageEventListener();
+ UsageStatsManagerInternal usmi = LocalServices.getService(UsageStatsManagerInternal.class);
+ usmi.registerListener(listener);
+
+ UsageEvents.Event event = new UsageEvents.Event(UsageEvents.Event.CONFIGURATION_CHANGE, 10);
+ usmi.reportEvent("com.android.test", 10, event.getEventType());
+ listener.setExpectation(10, event);
+ listener.mCountDownLatch.await(TIMEOUT, TimeUnit.MILLISECONDS);
+
+ usmi.unregisterListener(listener);
+ listener.reset();
+
+ usmi.reportEvent("com.android.test", 0, UsageEvents.Event.CHOOSER_ACTION);
+ Thread.sleep(TIMEOUT);
+ assertNull(listener.mLastReceivedEvent);
+ }
+
+ private static class TestUsageEventListener implements
+ UsageStatsManagerInternal.UsageEventListener {
+ UsageEvents.Event mLastReceivedEvent;
+ int mLastReceivedUserId;
+ UsageEvents.Event mExpectedEvent;
+ int mExpectedUserId;
+ CountDownLatch mCountDownLatch;
+
+ @Override
+ public void onUsageEvent(int userId, UsageEvents.Event event) {
+ mLastReceivedUserId = userId;
+ mLastReceivedEvent = event;
+ if (mCountDownLatch != null && userId == mExpectedUserId
+ && event.getEventType() == mExpectedEvent.getEventType()) {
+ mCountDownLatch.countDown();
+ }
+ }
+
+ private void setExpectation(int userId, UsageEvents.Event event) {
+ mExpectedUserId = userId;
+ mExpectedEvent = event;
+ mCountDownLatch = new CountDownLatch(1);
+ }
+
+ private void reset() {
+ mLastReceivedUserId = mExpectedUserId = -1;
+ mLastReceivedEvent = mExpectedEvent = null;
+ mCountDownLatch = null;
+ }
+ }
+}
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index f2bb91c66ac3..0c2fab83ee66 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -49,6 +49,8 @@ android_test {
// TODO: remove once Android migrates to JUnit 4.12,
// which provides assertThrows
"testng",
+ "junit",
+ "platform-compat-test-rules",
],
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
index 026db42d4d7a..640d6e599736 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -28,6 +28,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.PropertyInvalidatedCache;
+import android.compat.testing.PlatformCompatChangeRule;
import android.content.Context;
import android.graphics.Insets;
import android.graphics.Rect;
@@ -44,8 +45,10 @@ import android.hardware.display.VirtualDisplayConfig;
import android.hardware.input.InputManagerInternal;
import android.os.Handler;
import android.os.IBinder;
+import android.os.Process;
import android.view.Display;
import android.view.DisplayCutout;
+import android.view.DisplayEventReceiver;
import android.view.DisplayInfo;
import android.view.Surface;
import android.view.SurfaceControl;
@@ -57,13 +60,17 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.server.LocalServices;
import com.android.server.SystemService;
-import com.android.server.display.DisplayDeviceInfo;
import com.android.server.display.DisplayManagerService.SyncRoot;
import com.android.server.lights.LightsManager;
import com.android.server.wm.WindowManagerInternal;
+import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
+import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
+
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
@@ -80,6 +87,9 @@ public class DisplayManagerServiceTest {
private static final String VIRTUAL_DISPLAY_NAME = "Test Virtual Display";
private static final String PACKAGE_NAME = "com.android.frameworks.servicestests";
+ @Rule
+ public TestRule compatChangeRule = new PlatformCompatChangeRule();
+
private Context mContext;
private final DisplayManagerService.Injector mShortMockedInjector =
@@ -95,15 +105,31 @@ public class DisplayManagerServiceTest {
return SHORT_DEFAULT_DISPLAY_TIMEOUT_MILLIS;
}
};
- private final DisplayManagerService.Injector mBasicInjector =
- new DisplayManagerService.Injector() {
+
+ class BasicInjector extends DisplayManagerService.Injector {
+ @Override
+ VirtualDisplayAdapter getVirtualDisplayAdapter(SyncRoot syncRoot, Context context,
+ Handler handler, DisplayAdapter.Listener displayAdapterListener) {
+ return new VirtualDisplayAdapter(syncRoot, context, handler, displayAdapterListener,
+ (String name, boolean secure) -> mMockDisplayToken);
+ }
+ }
+
+ private final DisplayManagerService.Injector mBasicInjector = new BasicInjector();
+
+ private final DisplayManagerService.Injector mAllowNonNativeRefreshRateOverrideInjector =
+ new BasicInjector() {
@Override
- VirtualDisplayAdapter getVirtualDisplayAdapter(SyncRoot syncRoot,
- Context context, Handler handler,
- DisplayAdapter.Listener displayAdapterListener) {
- return new VirtualDisplayAdapter(syncRoot, context, handler,
- displayAdapterListener,
- (String name, boolean secure) -> mMockDisplayToken);
+ boolean getAllowNonNativeRefreshRateOverride() {
+ return true;
+ }
+ };
+
+ private final DisplayManagerService.Injector mDenyNonNativeRefreshRateOverrideInjector =
+ new BasicInjector() {
+ @Override
+ boolean getAllowNonNativeRefreshRateOverride() {
+ return false;
}
};
@@ -575,6 +601,337 @@ public class DisplayManagerServiceTest {
assertEquals(displayManager.getVirtualDisplaySurfaceInternal(mMockAppToken), surface);
}
+ /**
+ * Tests that there should be a display change notification if the frame rate overrides
+ * list is updated.
+ */
+ @Test
+ public void testShouldNotifyChangeWhenDisplayInfoFrameRateOverrideChanged() throws Exception {
+ DisplayManagerService displayManager =
+ new DisplayManagerService(mContext, mShortMockedInjector);
+ DisplayManagerService.BinderService displayManagerBinderService =
+ displayManager.new BinderService();
+ registerDefaultDisplays(displayManager);
+ displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
+
+ FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager, new float[]{60f});
+ FakeDisplayManagerCallback callback = registerDisplayListenerCallback(displayManager,
+ displayManagerBinderService, displayDevice);
+
+ int myUid = Process.myUid();
+ updateFrameRateOverride(displayManager, displayDevice,
+ new DisplayEventReceiver.FrameRateOverride[]{
+ new DisplayEventReceiver.FrameRateOverride(myUid, 30f),
+ });
+ assertTrue(callback.mCalled);
+ callback.clear();
+
+ updateFrameRateOverride(displayManager, displayDevice,
+ new DisplayEventReceiver.FrameRateOverride[]{
+ new DisplayEventReceiver.FrameRateOverride(myUid, 30f),
+ new DisplayEventReceiver.FrameRateOverride(1234, 30f),
+ });
+ assertFalse(callback.mCalled);
+
+ updateFrameRateOverride(displayManager, displayDevice,
+ new DisplayEventReceiver.FrameRateOverride[]{
+ new DisplayEventReceiver.FrameRateOverride(myUid, 20f),
+ new DisplayEventReceiver.FrameRateOverride(1234, 30f),
+ new DisplayEventReceiver.FrameRateOverride(5678, 30f),
+ });
+ assertTrue(callback.mCalled);
+ callback.clear();
+
+ updateFrameRateOverride(displayManager, displayDevice,
+ new DisplayEventReceiver.FrameRateOverride[]{
+ new DisplayEventReceiver.FrameRateOverride(1234, 30f),
+ new DisplayEventReceiver.FrameRateOverride(5678, 30f),
+ });
+ assertTrue(callback.mCalled);
+ callback.clear();
+
+ updateFrameRateOverride(displayManager, displayDevice,
+ new DisplayEventReceiver.FrameRateOverride[]{
+ new DisplayEventReceiver.FrameRateOverride(5678, 30f),
+ });
+ assertFalse(callback.mCalled);
+ }
+
+ /**
+ * Tests that the DisplayInfo is updated correctly with a frame rate override
+ */
+ @Test
+ public void testDisplayInfoFrameRateOverride() throws Exception {
+ DisplayManagerService displayManager =
+ new DisplayManagerService(mContext, mShortMockedInjector);
+ DisplayManagerService.BinderService displayManagerBinderService =
+ displayManager.new BinderService();
+ registerDefaultDisplays(displayManager);
+ displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
+
+ FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager,
+ new float[]{60f, 30f, 20f});
+ int displayId = getDisplayIdForDisplayDevice(displayManager, displayManagerBinderService,
+ displayDevice);
+ DisplayInfo displayInfo = displayManagerBinderService.getDisplayInfo(displayId);
+ assertEquals(60f, displayInfo.getRefreshRate(), 0.01f);
+
+ updateFrameRateOverride(displayManager, displayDevice,
+ new DisplayEventReceiver.FrameRateOverride[]{
+ new DisplayEventReceiver.FrameRateOverride(
+ Process.myUid(), 20f),
+ new DisplayEventReceiver.FrameRateOverride(
+ Process.myUid() + 1, 30f)
+ });
+ displayInfo = displayManagerBinderService.getDisplayInfo(displayId);
+ assertEquals(20f, displayInfo.getRefreshRate(), 0.01f);
+
+ // Changing the mode to 30Hz should not override the refresh rate to 20Hz anymore
+ // as 20 is not a divider of 30.
+ updateModeId(displayManager, displayDevice, 2);
+ displayInfo = displayManagerBinderService.getDisplayInfo(displayId);
+ assertEquals(30f, displayInfo.getRefreshRate(), 0.01f);
+ }
+
+ /**
+ * Tests that the frame rate override is updated accordingly to the
+ * allowNonNativeRefreshRateOverride policy.
+ */
+ @Test
+ public void testDisplayInfoNonNativeFrameRateOverride() throws Exception {
+ testDisplayInfoNonNativeFrameRateOverride(mDenyNonNativeRefreshRateOverrideInjector);
+ testDisplayInfoNonNativeFrameRateOverride(mAllowNonNativeRefreshRateOverrideInjector);
+ }
+
+ /**
+ * Tests that the mode reflects the frame rate override is in compat mode
+ */
+ @Test
+ @DisableCompatChanges({DisplayManagerService.DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE})
+ public void testDisplayInfoFrameRateOverrideModeCompat() throws Exception {
+ testDisplayInfoFrameRateOverrideModeCompat(/*compatChangeEnabled*/ false);
+ }
+
+ /**
+ * Tests that the mode reflects the physical display refresh rate when not in compat mode.
+ */
+ @Test
+ @EnableCompatChanges({DisplayManagerService.DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE})
+ public void testDisplayInfoFrameRateOverrideMode() throws Exception {
+ testDisplayInfoFrameRateOverrideModeCompat(/*compatChangeEnabled*/ true);
+ }
+
+ /**
+ * Tests that the mode reflects the frame rate override is in compat mode and accordingly to the
+ * allowNonNativeRefreshRateOverride policy.
+ */
+ @Test
+ @DisableCompatChanges({DisplayManagerService.DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE})
+ public void testDisplayInfoNonNativeFrameRateOverrideModeCompat() throws Exception {
+ testDisplayInfoNonNativeFrameRateOverrideMode(mDenyNonNativeRefreshRateOverrideInjector,
+ /*compatChangeEnabled*/ false);
+ testDisplayInfoNonNativeFrameRateOverrideMode(mAllowNonNativeRefreshRateOverrideInjector,
+ /*compatChangeEnabled*/ false);
+ }
+
+ /**
+ * Tests that the mode reflects the physical display refresh rate when not in compat mode.
+ */
+ @Test
+ @EnableCompatChanges({DisplayManagerService.DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE})
+ public void testDisplayInfoNonNativeFrameRateOverrideMode() throws Exception {
+ testDisplayInfoNonNativeFrameRateOverrideMode(mDenyNonNativeRefreshRateOverrideInjector,
+ /*compatChangeEnabled*/ true);
+ testDisplayInfoNonNativeFrameRateOverrideMode(mAllowNonNativeRefreshRateOverrideInjector,
+ /*compatChangeEnabled*/ true);
+ }
+
+ private void testDisplayInfoFrameRateOverrideModeCompat(boolean compatChangeEnabled)
+ throws Exception {
+ DisplayManagerService displayManager =
+ new DisplayManagerService(mContext, mShortMockedInjector);
+ DisplayManagerService.BinderService displayManagerBinderService =
+ displayManager.new BinderService();
+ registerDefaultDisplays(displayManager);
+ displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
+
+ FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager,
+ new float[]{60f, 30f, 20f});
+ int displayId = getDisplayIdForDisplayDevice(displayManager, displayManagerBinderService,
+ displayDevice);
+ DisplayInfo displayInfo = displayManagerBinderService.getDisplayInfo(displayId);
+ assertEquals(60f, displayInfo.getRefreshRate(), 0.01f);
+
+ updateFrameRateOverride(displayManager, displayDevice,
+ new DisplayEventReceiver.FrameRateOverride[]{
+ new DisplayEventReceiver.FrameRateOverride(
+ Process.myUid(), 20f),
+ new DisplayEventReceiver.FrameRateOverride(
+ Process.myUid() + 1, 30f)
+ });
+ displayInfo = displayManagerBinderService.getDisplayInfo(displayId);
+ assertEquals(20f, displayInfo.getRefreshRate(), 0.01f);
+ Display.Mode expectedMode;
+ if (compatChangeEnabled) {
+ expectedMode = new Display.Mode(1, 100, 200, 60f);
+ } else {
+ expectedMode = new Display.Mode(3, 100, 200, 20f);
+ }
+ assertEquals(expectedMode, displayInfo.getMode());
+ }
+
+ private void testDisplayInfoNonNativeFrameRateOverrideMode(
+ DisplayManagerService.Injector injector, boolean compatChangeEnabled) {
+ DisplayManagerService displayManager =
+ new DisplayManagerService(mContext, injector);
+ DisplayManagerService.BinderService displayManagerBinderService =
+ displayManager.new BinderService();
+ registerDefaultDisplays(displayManager);
+ displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
+
+ FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager,
+ new float[]{60f});
+ int displayId = getDisplayIdForDisplayDevice(displayManager, displayManagerBinderService,
+ displayDevice);
+ DisplayInfo displayInfo = displayManagerBinderService.getDisplayInfo(displayId);
+ assertEquals(60f, displayInfo.getRefreshRate(), 0.01f);
+
+ updateFrameRateOverride(displayManager, displayDevice,
+ new DisplayEventReceiver.FrameRateOverride[]{
+ new DisplayEventReceiver.FrameRateOverride(
+ Process.myUid(), 20f)
+ });
+ displayInfo = displayManagerBinderService.getDisplayInfo(displayId);
+ Display.Mode expectedMode;
+ if (compatChangeEnabled) {
+ expectedMode = new Display.Mode(1, 100, 200, 60f);
+ } else if (injector.getAllowNonNativeRefreshRateOverride()) {
+ expectedMode = new Display.Mode(255, 100, 200, 20f);
+ } else {
+ expectedMode = new Display.Mode(1, 100, 200, 60f);
+ }
+ assertEquals(expectedMode, displayInfo.getMode());
+ }
+
+ private void testDisplayInfoNonNativeFrameRateOverride(
+ DisplayManagerService.Injector injector) {
+ DisplayManagerService displayManager =
+ new DisplayManagerService(mContext, injector);
+ DisplayManagerService.BinderService displayManagerBinderService =
+ displayManager.new BinderService();
+ registerDefaultDisplays(displayManager);
+ displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
+
+ FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager,
+ new float[]{60f});
+ int displayId = getDisplayIdForDisplayDevice(displayManager, displayManagerBinderService,
+ displayDevice);
+ DisplayInfo displayInfo = displayManagerBinderService.getDisplayInfo(displayId);
+ assertEquals(60f, displayInfo.getRefreshRate(), 0.01f);
+
+ updateFrameRateOverride(displayManager, displayDevice,
+ new DisplayEventReceiver.FrameRateOverride[]{
+ new DisplayEventReceiver.FrameRateOverride(
+ Process.myUid(), 20f)
+ });
+ displayInfo = displayManagerBinderService.getDisplayInfo(displayId);
+ float expectedRefreshRate = injector.getAllowNonNativeRefreshRateOverride() ? 20f : 60f;
+ assertEquals(expectedRefreshRate, displayInfo.getRefreshRate(), 0.01f);
+ }
+
+ private int getDisplayIdForDisplayDevice(
+ DisplayManagerService displayManager,
+ DisplayManagerService.BinderService displayManagerBinderService,
+ FakeDisplayDevice displayDevice) {
+
+ final int[] displayIds = displayManagerBinderService.getDisplayIds();
+ assertTrue(displayIds.length > 0);
+ int displayId = Display.INVALID_DISPLAY;
+ for (int i = 0; i < displayIds.length; i++) {
+ DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayIds[i]);
+ if (displayDevice.getDisplayDeviceInfoLocked().equals(ddi)) {
+ displayId = displayIds[i];
+ break;
+ }
+ }
+ assertFalse(displayId == Display.INVALID_DISPLAY);
+ return displayId;
+ }
+
+ private void updateDisplayDeviceInfo(DisplayManagerService displayManager,
+ FakeDisplayDevice displayDevice,
+ DisplayDeviceInfo displayDeviceInfo) {
+ displayDevice.setDisplayDeviceInfo(displayDeviceInfo);
+ displayManager.getDisplayDeviceRepository()
+ .onDisplayDeviceEvent(displayDevice, DisplayAdapter.DISPLAY_DEVICE_EVENT_CHANGED);
+ Handler handler = displayManager.getDisplayHandler();
+ handler.runWithScissors(() -> {
+ }, 0 /* now */);
+ }
+
+ private void updateFrameRateOverride(DisplayManagerService displayManager,
+ FakeDisplayDevice displayDevice,
+ DisplayEventReceiver.FrameRateOverride[] frameRateOverrides) {
+ DisplayDeviceInfo displayDeviceInfo = new DisplayDeviceInfo();
+ displayDeviceInfo.copyFrom(displayDevice.getDisplayDeviceInfoLocked());
+ displayDeviceInfo.frameRateOverrides = frameRateOverrides;
+ updateDisplayDeviceInfo(displayManager, displayDevice, displayDeviceInfo);
+ }
+
+ private void updateModeId(DisplayManagerService displayManager,
+ FakeDisplayDevice displayDevice,
+ int modeId) {
+ DisplayDeviceInfo displayDeviceInfo = new DisplayDeviceInfo();
+ displayDeviceInfo.copyFrom(displayDevice.getDisplayDeviceInfoLocked());
+ displayDeviceInfo.modeId = modeId;
+ updateDisplayDeviceInfo(displayManager, displayDevice, displayDeviceInfo);
+ }
+
+ private FakeDisplayManagerCallback registerDisplayListenerCallback(
+ DisplayManagerService displayManager,
+ DisplayManagerService.BinderService displayManagerBinderService,
+ FakeDisplayDevice displayDevice) {
+ // Find the display id of the added FakeDisplayDevice
+ DisplayDeviceInfo displayDeviceInfo = displayDevice.getDisplayDeviceInfoLocked();
+
+ int displayId = getDisplayIdForDisplayDevice(displayManager, displayManagerBinderService,
+ displayDevice);
+
+ Handler handler = displayManager.getDisplayHandler();
+ handler.runWithScissors(() -> {
+ }, 0 /* now */);
+
+ // register display listener callback
+ FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback(displayId);
+ displayManagerBinderService.registerCallback(callback);
+ return callback;
+ }
+
+ private FakeDisplayDevice createFakeDisplayDevice(DisplayManagerService displayManager,
+ float[] refreshRates) {
+ FakeDisplayDevice displayDevice = new FakeDisplayDevice();
+ DisplayDeviceInfo displayDeviceInfo = new DisplayDeviceInfo();
+ int width = 100;
+ int height = 200;
+ displayDeviceInfo.supportedModes = new Display.Mode[refreshRates.length];
+ for (int i = 0; i < refreshRates.length; i++) {
+ displayDeviceInfo.supportedModes[i] =
+ new Display.Mode(i + 1, width, height, refreshRates[i]);
+ }
+ displayDeviceInfo.modeId = 1;
+ displayDeviceInfo.width = width;
+ displayDeviceInfo.height = height;
+ final Rect zeroRect = new Rect();
+ displayDeviceInfo.displayCutout = new DisplayCutout(
+ Insets.of(0, 10, 0, 0),
+ zeroRect, new Rect(0, 0, 10, 10), zeroRect, zeroRect);
+ displayDeviceInfo.flags = DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY;
+ displayDevice.setDisplayDeviceInfo(displayDeviceInfo);
+ displayManager.getDisplayDeviceRepository()
+ .onDisplayDeviceEvent(displayDevice, DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED);
+ return displayDevice;
+ }
+
private void registerDefaultDisplays(DisplayManagerService displayManager) {
Handler handler = displayManager.getDisplayHandler();
// Would prefer to call displayManager.onStart() directly here but it performs binderService
@@ -598,6 +955,10 @@ public class DisplayManagerServiceTest {
mCalled = true;
}
}
+
+ public void clear() {
+ mCalled = false;
+ }
}
private class FakeDisplayDevice extends DisplayDevice {
diff --git a/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java
index 59aff8d43755..b26d1efef2a8 100644
--- a/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java
@@ -23,6 +23,10 @@ import android.content.Context;
import android.hardware.power.stats.ChannelInfo;
import android.hardware.power.stats.EnergyConsumerResult;
import android.hardware.power.stats.EnergyMeasurement;
+import android.hardware.power.stats.PowerEntityInfo;
+import android.hardware.power.stats.StateInfo;
+import android.hardware.power.stats.StateResidency;
+import android.hardware.power.stats.StateResidencyResult;
import androidx.test.InstrumentationRegistry;
@@ -56,8 +60,13 @@ public class PowerStatsServiceTest {
private static final String MODEL_FILENAME = "modeltest";
private static final String PROTO_OUTPUT_FILENAME = "powerstats.proto";
private static final String CHANNEL_NAME = "channelname";
+ private static final String POWER_ENTITY_NAME = "powerentityinfo";
+ private static final String STATE_NAME = "stateinfo";
private static final int ENERGY_METER_COUNT = 8;
private static final int ENERGY_CONSUMER_COUNT = 2;
+ private static final int POWER_ENTITY_COUNT = 3;
+ private static final int STATE_INFO_COUNT = 5;
+ private static final int STATE_RESIDENCY_COUNT = 4;
private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
private PowerStatsService mService;
@@ -118,6 +127,43 @@ public class PowerStatsServiceTest {
public static final class TestPowerStatsHALWrapper implements IPowerStatsHALWrapper {
@Override
+ public PowerEntityInfo[] getPowerEntityInfo() {
+ PowerEntityInfo[] powerEntityInfoList = new PowerEntityInfo[POWER_ENTITY_COUNT];
+ for (int i = 0; i < powerEntityInfoList.length; i++) {
+ powerEntityInfoList[i] = new PowerEntityInfo();
+ powerEntityInfoList[i].powerEntityId = i;
+ powerEntityInfoList[i].powerEntityName = new String(POWER_ENTITY_NAME + i);
+ powerEntityInfoList[i].states = new StateInfo[STATE_INFO_COUNT];
+ for (int j = 0; j < powerEntityInfoList[i].states.length; j++) {
+ powerEntityInfoList[i].states[j] = new StateInfo();
+ powerEntityInfoList[i].states[j].stateId = j;
+ powerEntityInfoList[i].states[j].stateName = new String(STATE_NAME + i);
+ }
+ }
+ return powerEntityInfoList;
+ }
+
+ @Override
+ public StateResidencyResult[] getStateResidency(int[] powerEntityIds) {
+ StateResidencyResult[] stateResidencyResultList =
+ new StateResidencyResult[POWER_ENTITY_COUNT];
+ for (int i = 0; i < stateResidencyResultList.length; i++) {
+ stateResidencyResultList[i] = new StateResidencyResult();
+ stateResidencyResultList[i].powerEntityId = i;
+ stateResidencyResultList[i].stateResidencyData =
+ new StateResidency[STATE_RESIDENCY_COUNT];
+ for (int j = 0; j < stateResidencyResultList[i].stateResidencyData.length; j++) {
+ stateResidencyResultList[i].stateResidencyData[j] = new StateResidency();
+ stateResidencyResultList[i].stateResidencyData[j].totalTimeInStateMs = j;
+ stateResidencyResultList[i].stateResidencyData[j].totalStateEntryCount = j;
+ stateResidencyResultList[i].stateResidencyData[j].lastEntryTimestampMs = j;
+ }
+ }
+
+ return stateResidencyResultList;
+ }
+
+ @Override
public int[] getEnergyConsumerInfo() {
int[] energyConsumerInfoList = new int[ENERGY_CONSUMER_COUNT];
for (int i = 0; i < energyConsumerInfoList.length; i++) {
@@ -127,7 +173,7 @@ public class PowerStatsServiceTest {
}
@Override
- public EnergyConsumerResult[] getEnergyConsumed() {
+ public EnergyConsumerResult[] getEnergyConsumed(int[] energyConsumerIds) {
EnergyConsumerResult[] energyConsumedList =
new EnergyConsumerResult[ENERGY_CONSUMER_COUNT];
for (int i = 0; i < energyConsumedList.length; i++) {
@@ -151,7 +197,7 @@ public class PowerStatsServiceTest {
}
@Override
- public EnergyMeasurement[] readEnergyMeters() {
+ public EnergyMeasurement[] readEnergyMeters(int[] channelIds) {
EnergyMeasurement[] energyMeasurementList = new EnergyMeasurement[ENERGY_METER_COUNT];
for (int i = 0; i < energyMeasurementList.length; i++) {
energyMeasurementList[i] = new EnergyMeasurement();
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index 0ad669f32060..11fb0021be62 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -65,6 +65,7 @@ import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.usage.AppStandbyInfo;
import android.app.usage.UsageEvents;
+import android.app.usage.UsageStatsManagerInternal;
import android.appwidget.AppWidgetManager;
import android.content.Context;
import android.content.ContextWrapper;
@@ -86,9 +87,11 @@ import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener;
+import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
@@ -425,11 +428,18 @@ public class AppStandbyControllerTests {
@Before
public void setUp() throws Exception {
+ LocalServices.addService(
+ UsageStatsManagerInternal.class, mock(UsageStatsManagerInternal.class));
MyContextWrapper myContext = new MyContextWrapper(InstrumentationRegistry.getContext());
mInjector = new MyInjector(myContext, Looper.getMainLooper());
mController = setupController();
}
+ @After
+ public void tearDown() {
+ LocalServices.removeServiceForTest(UsageStatsManagerInternal.class);
+ }
+
@Test
public void testBoundWidgetPackageExempt() throws Exception {
assumeTrue(mInjector.getContext().getSystemService(AppWidgetManager.class) != null);
@@ -562,7 +572,7 @@ public class AppStandbyControllerTests {
UsageEvents.Event ev = new UsageEvents.Event();
ev.mPackage = packageName;
ev.mEventType = eventType;
- controller.reportEvent(ev, USER_ID);
+ controller.onUsageEvent(USER_ID, ev);
}
private int getStandbyBucket(AppStandbyController controller, String packageName) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaOrganizerTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaOrganizerTest.java
index 3220d1d6a990..1198ee2ba5f4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaOrganizerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaOrganizerTest.java
@@ -16,8 +16,13 @@
package com.android.server.wm;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.window.DisplayAreaOrganizer.FEATURE_ROOT;
+import static android.window.DisplayAreaOrganizer.FEATURE_RUNTIME_TASK_CONTAINER_FIRST;
import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -25,6 +30,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertThrows;
import android.content.res.Configuration;
import android.graphics.Rect;
@@ -55,9 +61,12 @@ import java.util.List;
public class DisplayAreaOrganizerTest extends WindowTestsBase {
private DisplayArea mTestDisplayArea;
+ private DisplayAreaOrganizerController mOrganizerController;
@Before
public void setUp() {
+ mOrganizerController =
+ mWm.mAtmService.mWindowOrganizerController.mDisplayAreaOrganizerController;
WindowContainer parentWindow = mDisplayContent.getDefaultTaskDisplayArea().getParent();
mTestDisplayArea = new DisplayArea(mWm, DisplayArea.Type.ANY,
"TestDisplayArea", FEATURE_VENDOR_FIRST);
@@ -76,8 +85,7 @@ public class DisplayAreaOrganizerTest extends WindowTestsBase {
private IDisplayAreaOrganizer registerMockOrganizer(int feature, Binder binder) {
final IDisplayAreaOrganizer organizer = createMockOrganizer(binder);
- mWm.mAtmService.mWindowOrganizerController.mDisplayAreaOrganizerController
- .registerOrganizer(organizer, feature);
+ mOrganizerController.registerOrganizer(organizer, feature);
return organizer;
}
@@ -87,16 +95,10 @@ public class DisplayAreaOrganizerTest extends WindowTestsBase {
return organizer;
}
- private void unregisterMockOrganizer(IDisplayAreaOrganizer organizer) {
- mWm.mAtmService.mWindowOrganizerController.mDisplayAreaOrganizerController
- .unregisterOrganizer(organizer);
- }
-
@Test
public void testRegisterOrganizer() throws RemoteException {
- IDisplayAreaOrganizer organizer = createMockOrganizer(new Binder());
- List<DisplayAreaAppearedInfo> infos = mWm.mAtmService.mWindowOrganizerController
- .mDisplayAreaOrganizerController
+ final IDisplayAreaOrganizer organizer = createMockOrganizer(new Binder());
+ List<DisplayAreaAppearedInfo> infos = mOrganizerController
.registerOrganizer(organizer, FEATURE_VENDOR_FIRST).getList();
// Return a list contains the DA, and no onDisplayAreaAppeared triggered.
@@ -108,16 +110,135 @@ public class DisplayAreaOrganizerTest extends WindowTestsBase {
}
@Test
+ public void testRegisterOrganizer_alreadyRegisteredFeature() {
+ registerMockOrganizer(FEATURE_VENDOR_FIRST);
+ assertThrows(IllegalStateException.class,
+ () -> registerMockOrganizer(FEATURE_VENDOR_FIRST));
+ }
+
+ @Test
+ public void testCreateTaskDisplayArea() {
+ final String newTdaName = "testTda";
+ final IDisplayAreaOrganizer organizer = createMockOrganizer(new Binder());
+ final DisplayAreaAppearedInfo tdaInfo = mOrganizerController.createTaskDisplayArea(
+ organizer, DEFAULT_DISPLAY, FEATURE_ROOT, newTdaName);
+
+ final int newTdaIndex =
+ mTestDisplayArea.getParent().mChildren.indexOf(mTestDisplayArea) + 1;
+ final WindowContainer wc = mTestDisplayArea.getParent().getChildAt(newTdaIndex);
+
+ // A new TaskDisplayArea is created on the top.
+ assertThat(wc).isInstanceOf(TaskDisplayArea.class);
+ assertThat(tdaInfo.getDisplayAreaInfo().displayId).isEqualTo(DEFAULT_DISPLAY);
+ assertThat(tdaInfo.getDisplayAreaInfo().token)
+ .isEqualTo(wc.mRemoteToken.toWindowContainerToken());
+
+ final TaskDisplayArea tda = wc.asTaskDisplayArea();
+
+ assertThat(tda.getName()).isEqualTo(newTdaName);
+ assertThat(tda.mFeatureId).isEqualTo(tdaInfo.getDisplayAreaInfo().featureId);
+ assertThat(tda.mCreatedByOrganizer).isTrue();
+ assertThat(tda.mOrganizer).isEqualTo(organizer);
+ }
+
+ @Test
+ public void testCreateTaskDisplayArea_incrementalTdaFeatureId() {
+ final String newTdaName = "testTda";
+ final IDisplayAreaOrganizer organizer = createMockOrganizer(new Binder());
+ final DisplayAreaAppearedInfo tdaInfo1 = mOrganizerController.createTaskDisplayArea(
+ organizer, DEFAULT_DISPLAY, FEATURE_ROOT, newTdaName);
+ final DisplayAreaAppearedInfo tdaInfo2 = mOrganizerController.createTaskDisplayArea(
+ organizer, DEFAULT_DISPLAY, FEATURE_ROOT, newTdaName);
+
+ // New created TDA has unique feature id starting from FEATURE_RUNTIME_TASK_CONTAINER_FIRST.
+ assertThat(tdaInfo1.getDisplayAreaInfo().featureId).isEqualTo(
+ FEATURE_RUNTIME_TASK_CONTAINER_FIRST);
+ assertThat(tdaInfo2.getDisplayAreaInfo().featureId).isEqualTo(
+ FEATURE_RUNTIME_TASK_CONTAINER_FIRST + 1);
+ }
+
+
+ @Test
+ public void testCreateTaskDisplayArea_invalidDisplayAndRoot() {
+ final IDisplayAreaOrganizer organizer = createMockOrganizer(new Binder());
+ assertThrows(IllegalArgumentException.class, () ->
+ mOrganizerController.createTaskDisplayArea(
+ organizer, SystemServicesTestRule.sNextDisplayId + 1, FEATURE_ROOT,
+ "testTda"));
+ assertThrows(IllegalArgumentException.class, () ->
+ mOrganizerController.createTaskDisplayArea(
+ organizer, DEFAULT_DISPLAY, FEATURE_ROOT - 1, "testTda"));
+ }
+
+ @Test
+ public void testDeleteTaskDisplayArea() {
+ final String newTdaName = "testTda";
+ final IDisplayAreaOrganizer organizer = createMockOrganizer(new Binder());
+ final DisplayAreaAppearedInfo tdaInfo = mOrganizerController.createTaskDisplayArea(
+ organizer, DEFAULT_DISPLAY, FEATURE_ROOT, newTdaName);
+ final int tdaFeatureId = tdaInfo.getDisplayAreaInfo().featureId;
+
+ final TaskDisplayArea newTda = mDisplayContent.getItemFromDisplayAreas(
+ da -> da.mFeatureId == tdaFeatureId ? da.asTaskDisplayArea() : null);
+ spyOn(newTda);
+
+ mOrganizerController.deleteTaskDisplayArea(newTda.mRemoteToken.toWindowContainerToken());
+
+ verify(newTda).remove();
+ verify(newTda).removeImmediately();
+ assertThat(newTda.mOrganizer).isNull();
+ assertThat(newTda.isRemoved()).isTrue();
+
+ final TaskDisplayArea curTda = mDisplayContent.getItemFromDisplayAreas(
+ da -> da.mFeatureId == tdaFeatureId ? da.asTaskDisplayArea() : null);
+
+ assertThat(curTda).isNull();
+ }
+
+ @Test
+ public void testUnregisterOrganizer_deleteNewCreatedTaskDisplayArea() {
+ final String newTdaName = "testTda";
+ final IDisplayAreaOrganizer organizer = createMockOrganizer(new Binder());
+ final DisplayAreaAppearedInfo tdaInfo = mOrganizerController.createTaskDisplayArea(
+ organizer, DEFAULT_DISPLAY, FEATURE_ROOT, newTdaName);
+ final int tdaFeatureId = tdaInfo.getDisplayAreaInfo().featureId;
+
+ final TaskDisplayArea newTda = mDisplayContent.getItemFromDisplayAreas(
+ da -> da.mFeatureId == tdaFeatureId ? da.asTaskDisplayArea() : null);
+ spyOn(newTda);
+
+ mOrganizerController.unregisterOrganizer(organizer);
+
+ verify(newTda).remove();
+ verify(newTda).removeImmediately();
+ assertThat(newTda.mOrganizer).isNull();
+ assertThat(newTda.isRemoved()).isTrue();
+
+ final TaskDisplayArea curTda = mDisplayContent.getItemFromDisplayAreas(
+ da -> da.mFeatureId == tdaFeatureId ? da.asTaskDisplayArea() : null);
+
+ assertThat(curTda).isNull();
+ }
+
+ @Test
+ public void testDeleteTaskDisplayArea_invalidTaskDisplayArea() {
+ final TaskDisplayArea tda = mDisplayContent.getDefaultTaskDisplayArea();
+ assertThrows(IllegalArgumentException.class, () ->
+ mOrganizerController.deleteTaskDisplayArea(
+ tda.mRemoteToken.toWindowContainerToken()));
+ }
+
+ @Test
public void testAppearedVanished() throws RemoteException {
- IDisplayAreaOrganizer organizer = registerMockOrganizer(FEATURE_VENDOR_FIRST);
- unregisterMockOrganizer(organizer);
+ final IDisplayAreaOrganizer organizer = registerMockOrganizer(FEATURE_VENDOR_FIRST);
+ mOrganizerController.unregisterOrganizer(organizer);
verify(organizer).onDisplayAreaVanished(any());
}
@Test
public void testChanged() throws RemoteException {
- IDisplayAreaOrganizer organizer = registerMockOrganizer(FEATURE_VENDOR_FIRST);
+ final IDisplayAreaOrganizer organizer = registerMockOrganizer(FEATURE_VENDOR_FIRST);
mDisplayContent.setBounds(new Rect(0, 0, 1000, 1000));
verify(organizer).onDisplayAreaInfoChanged(any());
@@ -137,7 +258,7 @@ public class DisplayAreaOrganizerTest extends WindowTestsBase {
assertThat(mTestDisplayArea.mOrganizer).isNotNull();
- unregisterMockOrganizer(createMockOrganizer(binder));
+ mOrganizerController.unregisterOrganizer(createMockOrganizer(binder));
assertThat(mTestDisplayArea.mOrganizer).isNull();
}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 8e56e5bb2d85..aa36e47a359b 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -82,6 +82,7 @@ import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.PackageMonitor;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.CollectionUtils;
@@ -90,7 +91,6 @@ import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.LocalServices;
import com.android.server.SystemService;
-import com.android.server.SystemService.TargetUser;
import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener;
import java.io.BufferedReader;
@@ -178,6 +178,8 @@ public class UsageStatsService extends SystemService implements
private final SparseArray<LinkedList<Event>> mReportedEvents = new SparseArray<>();
final SparseArray<ArraySet<String>> mUsageReporters = new SparseArray();
final SparseArray<ActivityData> mVisibleActivities = new SparseArray();
+ private final ArraySet<UsageStatsManagerInternal.UsageEventListener> mUsageEventListeners =
+ new ArraySet<>();
private static class ActivityData {
private final String mTaskRootPackage;
@@ -202,8 +204,24 @@ public class UsageStatsService extends SystemService implements
}
};
+ @VisibleForTesting
+ static class Injector {
+ AppStandbyInternal getAppStandbyController(Context context) {
+ return AppStandbyInternal.newAppStandbyController(
+ UsageStatsService.class.getClassLoader(), context);
+ }
+ }
+
+ private final Injector mInjector;
+
public UsageStatsService(Context context) {
+ this(context, new Injector());
+ }
+
+ @VisibleForTesting
+ UsageStatsService(Context context, Injector injector) {
super(context);
+ mInjector = injector;
}
@Override
@@ -214,8 +232,7 @@ public class UsageStatsService extends SystemService implements
mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
mHandler = new H(BackgroundThread.get().getLooper());
- mAppStandby = AppStandbyInternal.newAppStandbyController(
- UsageStatsService.class.getClassLoader(), getContext());
+ mAppStandby = mInjector.getAppStandbyController(getContext());
mAppTimeLimit = new AppTimeLimitController(
new AppTimeLimitController.TimeLimitCallbackListener() {
@@ -262,6 +279,11 @@ public class UsageStatsService extends SystemService implements
publishLocalService(UsageStatsManagerInternal.class, new LocalService());
publishLocalService(AppStandbyInternal.class, mAppStandby);
+ publishBinderServices();
+ }
+
+ @VisibleForTesting
+ void publishBinderServices() {
publishBinderService(Context.USAGE_STATS_SERVICE, new BinderService());
}
@@ -928,7 +950,10 @@ public class UsageStatsService extends SystemService implements
service.reportEvent(event);
}
- mAppStandby.reportEvent(event, userId);
+ final int size = mUsageEventListeners.size();
+ for (int i = 0; i < size; ++i) {
+ mUsageEventListeners.valueAt(i).onUsageEvent(userId, event);
+ }
}
/**
@@ -1151,6 +1176,25 @@ public class UsageStatsService extends SystemService implements
}
}
+ /**
+ * Called via the local interface.
+ */
+ private void registerListener(@NonNull UsageStatsManagerInternal.UsageEventListener listener) {
+ synchronized (mLock) {
+ mUsageEventListeners.add(listener);
+ }
+ }
+
+ /**
+ * Called via the local interface.
+ */
+ private void unregisterListener(
+ @NonNull UsageStatsManagerInternal.UsageEventListener listener) {
+ synchronized (mLock) {
+ mUsageEventListeners.remove(listener);
+ }
+ }
+
private String buildFullToken(String packageName, String token) {
final StringBuilder sb = new StringBuilder(packageName.length() + token.length() + 1);
sb.append(packageName);
@@ -2317,6 +2361,22 @@ public class UsageStatsService extends SystemService implements
public boolean updatePackageMappingsData() {
return UsageStatsService.this.updatePackageMappingsData();
}
+
+ /**
+ * Register a listener that will be notified of every new usage event.
+ */
+ @Override
+ public void registerListener(@NonNull UsageEventListener listener) {
+ UsageStatsService.this.registerListener(listener);
+ }
+
+ /**
+ * Unregister a listener from being notified of every new usage event.
+ */
+ @Override
+ public void unregisterListener(@NonNull UsageEventListener listener) {
+ UsageStatsService.this.unregisterListener(listener);
+ }
}
private class MyPackageMonitor extends PackageMonitor {
diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
index fa0574a503f1..9738e58543e1 100644
--- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
@@ -1064,6 +1064,31 @@ public class PackageWatchdogTest {
}
/**
+ * Ensure that the correct mitigation counts are sent to the boot loop observer.
+ */
+ @Test
+ public void testMultipleBootLoopMitigation() {
+ PackageWatchdog watchdog = createWatchdog();
+ TestObserver bootObserver = new TestObserver(OBSERVER_NAME_1);
+ watchdog.registerHealthObserver(bootObserver);
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT; j++) {
+ watchdog.noteBoot();
+ }
+ }
+
+ moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_DEESCALATION_WINDOW_MS + 1);
+
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT; j++) {
+ watchdog.noteBoot();
+ }
+ }
+
+ assertThat(bootObserver.mBootMitigationCounts).isEqualTo(List.of(1, 2, 3, 4, 1, 2, 3, 4));
+ }
+
+ /**
* Ensure that passing a null list of failed packages does not cause any mitigation logic to
* execute.
*/
@@ -1267,6 +1292,7 @@ public class PackageWatchdogTest {
final List<String> mHealthCheckFailedPackages = new ArrayList<>();
final List<String> mMitigatedPackages = new ArrayList<>();
final List<Integer> mMitigationCounts = new ArrayList<>();
+ final List<Integer> mBootMitigationCounts = new ArrayList<>();
TestObserver(String name) {
mName = name;
@@ -1304,12 +1330,13 @@ public class PackageWatchdogTest {
return mMayObservePackages;
}
- public int onBootLoop() {
+ public int onBootLoop(int level) {
return mImpact;
}
- public boolean executeBootLoopMitigation() {
+ public boolean executeBootLoopMitigation(int level) {
mMitigatedBootLoop = true;
+ mBootMitigationCounts.add(level);
return true;
}
diff --git a/tests/net/common/java/android/net/MatchAllNetworkSpecifierTest.kt b/tests/net/common/java/android/net/MatchAllNetworkSpecifierTest.kt
index a67156a74d18..a5e44d59fcab 100644
--- a/tests/net/common/java/android/net/MatchAllNetworkSpecifierTest.kt
+++ b/tests/net/common/java/android/net/MatchAllNetworkSpecifierTest.kt
@@ -53,8 +53,13 @@ class MatchAllNetworkSpecifierTest {
assertParcelSane(MatchAllNetworkSpecifier(), 0)
}
- @Test @IgnoreAfter(Build.VERSION_CODES.R)
- fun testCanBeSatisfiedBy_BeforeS() {
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.Q)
+ @IgnoreAfter(Build.VERSION_CODES.R)
+ // Only run this test on Android R.
+ // The method - satisfiedBy() has changed to canBeSatisfiedBy() starting from Android R, so the
+ // method - canBeSatisfiedBy() cannot be found when running this test on Android Q.
+ fun testCanBeSatisfiedBy_OnlyForR() {
// MatchAllNetworkSpecifier didn't follow its parent class to change the satisfiedBy() to
// canBeSatisfiedBy(), so if a caller calls MatchAllNetworkSpecifier#canBeSatisfiedBy(), the
// NetworkSpecifier#canBeSatisfiedBy() will be called actually, and false will be returned.
diff --git a/tools/codegen/src/com/android/codegen/Generators.kt b/tools/codegen/src/com/android/codegen/Generators.kt
index 6c6d011cfede..5fc800b09ee9 100644
--- a/tools/codegen/src/com/android/codegen/Generators.kt
+++ b/tools/codegen/src/com/android/codegen/Generators.kt
@@ -5,8 +5,6 @@ import com.github.javaparser.ast.body.MethodDeclaration
import com.github.javaparser.ast.body.VariableDeclarator
import com.github.javaparser.ast.expr.AnnotationExpr
import com.github.javaparser.ast.expr.ArrayInitializerExpr
-import com.github.javaparser.ast.expr.LiteralExpr
-import com.github.javaparser.ast.expr.UnaryExpr
import java.io.File
@@ -163,7 +161,12 @@ fun ClassPrinter.generateCopyConstructor() {
return
}
- +"/** Copy constructor */"
+ +"/**"
+ +" * Copy constructor"
+ if (FeatureFlag.COPY_CONSTRUCTOR.hidden) {
+ +" * @hide"
+ }
+ +" */"
+GENERATED_MEMBER_HEADER
"public $ClassName(@$NonNull $ClassName orig)" {
fields.forEachApply {
diff --git a/tools/codegen/src/com/android/codegen/SharedConstants.kt b/tools/codegen/src/com/android/codegen/SharedConstants.kt
index 2e176c3d3bec..6a635d0e6181 100644
--- a/tools/codegen/src/com/android/codegen/SharedConstants.kt
+++ b/tools/codegen/src/com/android/codegen/SharedConstants.kt
@@ -1,7 +1,7 @@
package com.android.codegen
const val CODEGEN_NAME = "codegen"
-const val CODEGEN_VERSION = "1.0.20"
+const val CODEGEN_VERSION = "1.0.21"
const val CANONICAL_BUILDER_CLASS = "Builder"
const val BASE_BUILDER_CLASS = "BaseBuilder"
diff --git a/tools/hiddenapi/exclude.sh b/tools/hiddenapi/exclude.sh
index 18c40546fd02..73eacc0641e5 100755
--- a/tools/hiddenapi/exclude.sh
+++ b/tools/hiddenapi/exclude.sh
@@ -35,7 +35,7 @@ TEAMS=LIBCORE
PACKAGES=$(for t in $TEAMS; do echo $(eval echo \${${t}_PACKAGES}); done)
RE=$(echo ${PACKAGES} | sed "s/ /|/g")
git show --name-only --pretty=format: $1 | grep "config/hiddenapi-.*txt" | while read file; do
- ENTRIES=$(grep -E "^L(${RE})/" <(git show $1:$file))
+ ENTRIES=$(grep -E "^L(${RE})/" || true <(git show $1:$file))
if [[ -n "${ENTRIES}" ]]; then
echo -e "\e[1m\e[31m$file $1 contains the following entries\e[0m"
echo -e "\e[1m\e[31mfor packages that are handled using UnsupportedAppUsage. Please remove\e[0m"
diff --git a/wifi/java/android/net/wifi/SoftApConfiguration.java b/wifi/java/android/net/wifi/SoftApConfiguration.java
index 9f9d7f3c3051..fddc8899a0c8 100644
--- a/wifi/java/android/net/wifi/SoftApConfiguration.java
+++ b/wifi/java/android/net/wifi/SoftApConfiguration.java
@@ -538,6 +538,15 @@ public final class SoftApConfiguration implements Parcelable {
if (!SdkLevel.isAtLeastS()) {
throw new UnsupportedOperationException();
}
+ return getChannelsInternal();
+ }
+
+ /**
+ * Internal version bypassing SdkLevel checks
+ * TODO(b/173791707): find a better way to allow Wifi to call its own new S APIs.
+ * @hide
+ */
+ public @NonNull SparseIntArray getChannelsInternal() {
return mChannels.clone();
}
diff --git a/wifi/java/android/net/wifi/SoftApInfo.java b/wifi/java/android/net/wifi/SoftApInfo.java
index 9a16facfec26..55c2f1759952 100644
--- a/wifi/java/android/net/wifi/SoftApInfo.java
+++ b/wifi/java/android/net/wifi/SoftApInfo.java
@@ -183,6 +183,15 @@ public final class SoftApInfo implements Parcelable {
if (!SdkLevel.isAtLeastS()) {
throw new UnsupportedOperationException();
}
+ return getWifiStandardInternal();
+ }
+
+ /**
+ * Internal version bypassing SdkLevel checks
+ * TODO(b/173791707): find a better way to allow Wifi to call its own new S APIs.
+ * @hide
+ */
+ public @WifiAnnotations.WifiStandard int getWifiStandardInternal() {
return mWifiStandard;
}