summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.clang-format13
-rw-r--r--PREUPLOAD.cfg10
-rw-r--r--apex/statsd/aidl/android/os/IStatsd.aidl (renamed from apex/statsd/aidl/android/os/IStatsManager.aidl)2
-rw-r--r--apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java8
-rw-r--r--api/current.txt18
-rwxr-xr-x[-rw-r--r--]api/system-current.txt71
-rw-r--r--api/test-current.txt12
-rw-r--r--cmds/statsd/src/StatsService.cpp14
-rw-r--r--cmds/statsd/src/StatsService.h6
-rw-r--r--core/java/android/app/Activity.java1
-rw-r--r--core/java/android/app/ActivityThread.java18
-rw-r--r--core/java/android/app/StatsManager.java26
-rw-r--r--core/java/android/app/SystemServiceRegistry.java11
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java47
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl3
-rw-r--r--core/java/android/bluetooth/BluetoothDevice.java127
-rw-r--r--core/java/android/content/Intent.java1
-rw-r--r--core/java/android/content/pm/ActivityInfo.java31
-rw-r--r--core/java/android/content/pm/PackageInstaller.java3
-rw-r--r--core/java/android/hardware/display/DisplayManagerInternal.java6
-rw-r--r--core/java/android/hardware/soundtrigger/ModelParams.aidl37
-rw-r--r--core/java/android/hardware/soundtrigger/SoundTrigger.aidl1
-rw-r--r--core/java/android/hardware/soundtrigger/SoundTrigger.java59
-rw-r--r--core/java/android/hardware/soundtrigger/SoundTriggerModule.java53
-rw-r--r--core/java/android/os/BatteryStats.java66
-rw-r--r--core/java/android/os/BatteryStatsManager.java118
-rw-r--r--core/java/android/os/connectivity/WifiBatteryStats.java9
-rw-r--r--core/java/android/os/storage/StorageManager.java4
-rw-r--r--core/java/android/permission/PermissionControllerService.java4
-rw-r--r--core/java/android/provider/ContactsContract.java4
-rw-r--r--core/java/android/provider/DeviceConfig.java114
-rw-r--r--core/java/android/provider/Telephony.java11
-rw-r--r--core/java/android/security/keymaster/KeymasterDefs.java1
-rw-r--r--core/java/android/service/controls/BooleanAction.java19
-rw-r--r--core/java/android/service/controls/Control.java20
-rw-r--r--core/java/android/service/controls/ControlAction.java58
-rw-r--r--core/java/android/service/controls/ControlButton.java18
-rw-r--r--core/java/android/service/controls/ControlState.java217
-rw-r--r--core/java/android/service/controls/ControlTemplate.java28
-rw-r--r--core/java/android/service/controls/DiscreteToggleTemplate.java23
-rw-r--r--core/java/android/service/controls/FloatAction.java18
-rw-r--r--core/java/android/service/controls/RangeTemplate.java41
-rw-r--r--core/java/android/service/controls/ThumbnailTemplate.java24
-rw-r--r--core/java/android/service/controls/ToggleTemplate.java19
-rw-r--r--core/java/android/text/format/DateUtils.java6
-rw-r--r--core/java/android/util/CloseGuard.java138
-rw-r--r--core/java/android/util/FeatureFlagUtils.java1
-rw-r--r--core/java/android/util/StatsLog.java18
-rw-r--r--core/java/android/view/Display.java26
-rw-r--r--core/java/android/view/DisplayInfo.java12
-rw-r--r--core/java/android/view/IWindowManager.aidl12
-rw-r--r--core/java/android/view/SurfaceControl.java49
-rw-r--r--core/java/android/view/Window.java38
-rw-r--r--core/java/android/view/WindowManager.java40
-rw-r--r--core/java/android/view/accessibility/AccessibilityCache.java58
-rw-r--r--core/java/android/view/accessibility/AccessibilityInteractionClient.java37
-rw-r--r--core/java/android/view/accessibility/AccessibilityWindowInfo.java29
-rw-r--r--core/java/android/widget/RemoteViews.java23
-rw-r--r--core/java/com/android/internal/app/AbstractResolverComparator.java1
-rw-r--r--core/java/com/android/internal/app/ISoundTriggerService.aidl13
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java5
-rw-r--r--core/jni/android/graphics/BitmapFactory.cpp5
-rw-r--r--core/jni/android_hardware_SoundTrigger.cpp104
-rw-r--r--core/jni/android_view_SurfaceControl.cpp36
-rw-r--r--core/res/res/values/attrs_manifest.xml24
-rw-r--r--core/res/res/values/config.xml13
-rw-r--r--core/res/res/values/public.xml4
-rw-r--r--core/res/res/values/strings.xml70
-rw-r--r--core/res/res/values/symbols.xml1
-rw-r--r--core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java2
-rw-r--r--core/tests/coretests/Android.bp1
-rw-r--r--core/tests/coretests/src/android/provider/DeviceConfigTest.java60
-rw-r--r--core/tests/coretests/src/android/util/CloseGuardTest.java98
-rw-r--r--core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java16
-rw-r--r--graphics/java/android/graphics/FontFamily.java9
-rw-r--r--keystore/java/android/security/keystore/AttestationUtils.java5
-rw-r--r--media/java/android/media/AudioAttributes.java14
-rw-r--r--media/java/android/media/soundtrigger/SoundTriggerManager.java96
-rwxr-xr-x[-rw-r--r--]media/java/android/media/tv/ITvInputService.aidl1
-rwxr-xr-x[-rw-r--r--]media/java/android/media/tv/TvInputService.java30
-rw-r--r--media/jni/soundpool/StreamManager.cpp3
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java3
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarShadeControllerImpl.java85
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java38
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java3
-rw-r--r--packages/Incremental/NativeAdbDataLoader/Android.bp22
-rw-r--r--packages/Incremental/NativeAdbDataLoader/AndroidManifest.xml39
-rw-r--r--packages/Incremental/NativeAdbDataLoader/jni/Android.bp37
-rw-r--r--packages/Incremental/NativeAdbDataLoader/jni/com_android_incremental_nativeadb_DataLoaderService.cpp519
-rw-r--r--packages/Incremental/NativeAdbDataLoader/res/values/strings.xml19
-rw-r--r--packages/Incremental/NativeAdbDataLoader/src/com/android/incremental/nativeadb/NativeAdbDataLoaderService.java32
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java8
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/OWNERS9
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java2
-rw-r--r--packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java17
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java23
-rw-r--r--packages/SystemUI/Android.bp2
-rw-r--r--packages/SystemUI/plugin_core/Android.bp4
-rw-r--r--packages/SystemUI/src/com/android/systemui/BatteryMeterView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/Dependency.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeEvent.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeLog.java66
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/Event.java29
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/RichEvent.java48
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/SysuiLog.java40
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java45
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationUpdateHandler.java60
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImpl.java51
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinator.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java200
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifLog.java92
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeControllerImpl.java236
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java211
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java55
-rw-r--r--packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingSecondaryUserActivity.java56
-rw-r--r--packages/SystemUI/src/com/android/systemui/wm/DisplayLayout.java474
-rw-r--r--packages/SystemUI/src/com/android/systemui/wm/DisplayWindowController.java56
-rw-r--r--packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java330
-rw-r--r--packages/SystemUI/tests/Android.mk3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/log/RichEventTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/log/SysuiLogTest.java59
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImplTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinatorTest.java152
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinatorTest.java188
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java34
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java136
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java30
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java14
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/DeviceConfigProxyFake.java13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wm/DisplayLayoutTest.java141
-rw-r--r--packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java25
-rw-r--r--services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java2
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java184
-rw-r--r--services/core/java/com/android/server/GnssManagerService.java1
-rw-r--r--services/core/java/com/android/server/LocationManagerService.java129
-rw-r--r--services/core/java/com/android/server/PackageWatchdog.java32
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java32
-rw-r--r--services/core/java/com/android/server/TelephonyRegistry.java5
-rw-r--r--services/core/java/com/android/server/am/LmkdConnection.java27
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java81
-rw-r--r--services/core/java/com/android/server/appop/AppOpsService.java8
-rw-r--r--services/core/java/com/android/server/audio/AudioDeviceInventory.java51
-rw-r--r--services/core/java/com/android/server/display/DisplayDevice.java18
-rw-r--r--services/core/java/com/android/server/display/DisplayDeviceInfo.java16
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java28
-rw-r--r--services/core/java/com/android/server/display/LocalDisplayAdapter.java46
-rw-r--r--services/core/java/com/android/server/display/LogicalDisplay.java27
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecKeycode.java4
-rw-r--r--services/core/java/com/android/server/location/LocationSettingsStore.java109
-rw-r--r--services/core/java/com/android/server/location/LocationUsageLogger.java (renamed from services/core/java/com/android/server/LocationUsageLogger.java)220
-rw-r--r--services/core/java/com/android/server/notification/NotificationComparator.java12
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java2
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java8
-rw-r--r--services/core/java/com/android/server/power/ShutdownThread.java29
-rw-r--r--services/core/java/com/android/server/storage/StorageSessionController.java28
-rw-r--r--services/core/java/com/android/server/storage/StorageUserConnection.java14
-rw-r--r--services/core/java/com/android/server/timedetector/TimeDetectorService.java11
-rw-r--r--services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java (renamed from services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java)86
-rwxr-xr-x[-rw-r--r--]services/core/java/com/android/server/tv/TvInputManagerService.java10
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java22
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java43
-rw-r--r--services/core/java/com/android/server/wm/RecentTasks.java1
-rw-r--r--services/core/java/com/android/server/wm/ShellRoot.java74
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotPersister.java11
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java59
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java2
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java40
-rw-r--r--services/java/com/android/server/SystemServer.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/GnssManagerServiceTest.java1
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java20
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java32
-rw-r--r--services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java11
-rw-r--r--services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java (renamed from services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeDetectorStrategyTest.java)10
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java45
-rw-r--r--services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java77
-rw-r--r--services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java99
-rw-r--r--telephony/common/com/android/internal/telephony/TelephonyPermissions.java153
-rw-r--r--telephony/java/android/telephony/Annotation.java3
-rw-r--r--telephony/java/android/telephony/SubscriptionInfo.java37
-rw-r--r--telephony/java/android/telephony/SubscriptionManager.java6
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java98
-rw-r--r--telephony/java/android/telephony/data/ApnSetting.java11
-rw-r--r--telephony/java/com/android/internal/telephony/PhoneConstants.java5
-rw-r--r--tests/ApkVerityTest/Android.bp4
-rw-r--r--tests/ManagedProfileLifecycleStressTest/app/DummyDPC/Android.bp1
-rw-r--r--wifi/java/android/net/wifi/IWifiManager.aidl2
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java15
-rw-r--r--wifi/java/com/android/server/wifi/BaseWifiService.java3
219 files changed, 6577 insertions, 2031 deletions
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 000000000000..03af56d64062
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,13 @@
+BasedOnStyle: Google
+
+AccessModifierOffset: -4
+AlignOperands: false
+AllowShortFunctionsOnASingleLine: Inline
+AlwaysBreakBeforeMultilineStrings: false
+ColumnLimit: 100
+CommentPragmas: NOLINT:.*
+ConstructorInitializerIndentWidth: 6
+ContinuationIndentWidth: 8
+IndentWidth: 4
+PenaltyBreakBeforeFirstCallParameter: 100000
+SpacesBeforeTrailingComments: 1
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 68311176a783..78e72bf39586 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,3 +1,13 @@
+[Builtin Hooks]
+clang_format = true
+
+[Builtin Hooks Options]
+# Only turn on clang-format check for the following subfolders.
+clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
+ cmds/hid/
+ cmds/input/
+ libs/input/
+
[Hook Scripts]
checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
diff --git a/apex/statsd/aidl/android/os/IStatsManager.aidl b/apex/statsd/aidl/android/os/IStatsd.aidl
index cc62f07a3750..cffc6ce6e4df 100644
--- a/apex/statsd/aidl/android/os/IStatsManager.aidl
+++ b/apex/statsd/aidl/android/os/IStatsd.aidl
@@ -24,7 +24,7 @@ import android.os.ParcelFileDescriptor;
* Binder interface to communicate with the statistics management service.
* {@hide}
*/
-interface IStatsManager {
+interface IStatsd {
/**
* Tell the stats daemon that the android system server is up and running.
*/
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
index 6fb3bc47859d..bc7716e5f6eb 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
@@ -79,7 +79,7 @@ import android.os.HandlerThread;
import android.os.IBinder;
import android.os.IPullAtomCallback;
import android.os.IStatsCompanionService;
-import android.os.IStatsManager;
+import android.os.IStatsd;
import android.os.IStoraged;
import android.os.IThermalEventListener;
import android.os.IThermalService;
@@ -268,7 +268,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
private final AlarmManager mAlarmManager;
private final INetworkStatsService mNetworkStatsService;
@GuardedBy("sStatsdLock")
- private static IStatsManager sStatsd;
+ private static IStatsd sStatsd;
private static final Object sStatsdLock = new Object();
private final OnAlarmListener mAnomalyAlarmListener = new AnomalyAlarmListener();
@@ -2743,8 +2743,8 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
* Note: This should only be called from sayHiToStatsd. All other clients should use the cached
* sStatsd with a null check.
*/
- private static IStatsManager fetchStatsdService() {
- return IStatsManager.Stub.asInterface(ServiceManager.getService("stats"));
+ private static IStatsd fetchStatsdService() {
+ return IStatsd.Stub.asInterface(ServiceManager.getService("stats"));
}
public static final class Lifecycle extends SystemService {
diff --git a/api/current.txt b/api/current.txt
index 8f1440dcb72d..6cbdf733a7ef 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1061,6 +1061,7 @@ package android {
field public static final int popupWindowStyle = 16842870; // 0x1010076
field public static final int port = 16842793; // 0x1010029
field public static final int positiveButtonText = 16843253; // 0x10101f5
+ field public static final int preferMinimalPostProcessing = 16844300; // 0x101060c
field public static final int preferenceCategoryStyle = 16842892; // 0x101008c
field public static final int preferenceFragmentStyle = 16844038; // 0x1010506
field public static final int preferenceInformationStyle = 16842893; // 0x101008d
@@ -6739,6 +6740,7 @@ package android.app.admin {
method @Nullable public java.util.Set<java.lang.String> getCrossProfileCalendarPackages(@NonNull android.content.ComponentName);
method public boolean getCrossProfileCallerIdDisabled(@NonNull android.content.ComponentName);
method public boolean getCrossProfileContactsSearchDisabled(@NonNull android.content.ComponentName);
+ method @NonNull public java.util.Set<java.lang.String> getCrossProfilePackages(@NonNull android.content.ComponentName);
method @NonNull public java.util.List<java.lang.String> getCrossProfileWidgetProviders(@NonNull android.content.ComponentName);
method public int getCurrentFailedPasswordAttempts();
method @Nullable public java.util.List<java.lang.String> getDelegatePackages(@NonNull android.content.ComponentName, @NonNull String);
@@ -6856,6 +6858,7 @@ package android.app.admin {
method public void setCrossProfileCalendarPackages(@NonNull android.content.ComponentName, @Nullable java.util.Set<java.lang.String>);
method public void setCrossProfileCallerIdDisabled(@NonNull android.content.ComponentName, boolean);
method public void setCrossProfileContactsSearchDisabled(@NonNull android.content.ComponentName, boolean);
+ method public void setCrossProfilePackages(@NonNull android.content.ComponentName, @NonNull java.util.Set<java.lang.String>);
method public void setDefaultSmsApplication(@NonNull android.content.ComponentName, @NonNull String);
method public void setDelegatedScopes(@NonNull android.content.ComponentName, @NonNull String, @NonNull java.util.List<java.lang.String>);
method public void setDeviceOwnerLockScreenInfo(@NonNull android.content.ComponentName, CharSequence);
@@ -11183,6 +11186,7 @@ package android.content.pm {
field public String parentActivityName;
field public String permission;
field public int persistableMode;
+ field public boolean preferMinimalPostProcessing;
field public int screenOrientation;
field public int softInputMode;
field public String targetActivity;
@@ -45605,6 +45609,7 @@ package android.telephony {
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean doesSwitchMultiSimConfigTriggerReboot();
method public int getActiveModemCount();
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public java.util.List<android.telephony.CellInfo> getAllCellInfo();
+ method @NonNull public static int[] getAllNetworkTypes();
method public int getCallState();
method public int getCardIdForDefaultEuicc();
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @WorkerThread public android.os.PersistableBundle getCarrierConfig();
@@ -45977,6 +45982,7 @@ package android.telephony.data {
field public static final int TYPE_MCX = 1024; // 0x400
field public static final int TYPE_MMS = 2; // 0x2
field public static final int TYPE_SUPL = 4; // 0x4
+ field public static final int TYPE_XCAP = 2048; // 0x800
}
public static class ApnSetting.Builder {
@@ -47286,7 +47292,7 @@ package android.text.format {
field public static final long WEEK_IN_MILLIS = 604800000L; // 0x240c8400L
field public static final String YEAR_FORMAT = "%Y";
field public static final String YEAR_FORMAT_TWO_DIGITS = "%g";
- field public static final long YEAR_IN_MILLIS = 31449600000L; // 0x7528ad000L
+ field @Deprecated public static final long YEAR_IN_MILLIS = 31449600000L; // 0x7528ad000L
field @Deprecated public static final int[] sameMonthTable;
field @Deprecated public static final int[] sameYearTable;
}
@@ -48725,6 +48731,13 @@ package android.util {
ctor public Base64OutputStream(java.io.OutputStream, int);
}
+ public final class CloseGuard {
+ ctor public CloseGuard();
+ method public void close();
+ method public void open(@NonNull String);
+ method public void warnIfOpen();
+ }
+
@Deprecated public final class Config {
field @Deprecated public static final boolean DEBUG = false;
field @Deprecated public static final boolean LOGD = true;
@@ -49512,6 +49525,7 @@ package android.view {
method @Deprecated public float[] getSupportedRefreshRates();
method @Deprecated public int getWidth();
method public boolean isHdr();
+ method public boolean isMinimalPostProcessingSupported();
method public boolean isValid();
method public boolean isWideColorGamut();
field public static final int DEFAULT_DISPLAY = 0; // 0x0
@@ -52537,6 +52551,7 @@ package android.view {
method public abstract void setNavigationBarColor(@ColorInt int);
method public void setNavigationBarContrastEnforced(boolean);
method public void setNavigationBarDividerColor(@ColorInt int);
+ method public void setPreferMinimalPostProcessing(boolean);
method public void setReenterTransition(android.transition.Transition);
method public abstract void setResizingCaptionDrawable(android.graphics.drawable.Drawable);
method public final void setRestrictedCaptionAreaListener(android.view.Window.OnRestrictedCaptionAreaChangedListener);
@@ -52854,6 +52869,7 @@ package android.view {
field public int layoutInDisplayCutoutMode;
field @Deprecated public int memoryType;
field public String packageName;
+ field public boolean preferMinimalPostProcessing;
field public int preferredDisplayModeId;
field @Deprecated public float preferredRefreshRate;
field public int rotationAnimation;
diff --git a/api/system-current.txt b/api/system-current.txt
index 472f1ecbf0b4..678f4f5f5923 100644..100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1423,15 +1423,24 @@ package android.bluetooth {
public final class BluetoothDevice implements android.os.Parcelable {
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean cancelBondProcess();
+ method public boolean cancelPairing();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getBatteryLevel();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getMessageAccessPermission();
method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public byte[] getMetadata(int);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getPhonebookAccessPermission();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getSimAccessPermission();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isBondingInitiatedLocally();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isConnected();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isEncrypted();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean isInSilenceMode();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean removeBond();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean setAlias(@NonNull String);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setMessageAccessPermission(int);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setMetadata(int, @NonNull byte[]);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setPhonebookAccessPermission(int);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setPin(@Nullable String);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setSilenceMode(boolean);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setSimAccessPermission(int);
field public static final int ACCESS_ALLOWED = 1; // 0x1
field public static final int ACCESS_REJECTED = 2; // 0x2
field public static final int ACCESS_UNKNOWN = 0; // 0x0
@@ -3410,6 +3419,14 @@ package android.hardware.soundtrigger {
field public static final int STATUS_OK = 0; // 0x0
}
+ public static final class SoundTrigger.ModelParamRange implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.hardware.soundtrigger.SoundTrigger.ModelParamRange> CREATOR;
+ field public final int end;
+ field public final int start;
+ }
+
public static final class SoundTrigger.ModuleProperties implements android.os.Parcelable {
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
@@ -3879,6 +3896,7 @@ package android.media {
field public static final int FLAG_BYPASS_INTERRUPTION_POLICY = 64; // 0x40
field public static final int FLAG_BYPASS_MUTE = 128; // 0x80
field public static final int FLAG_HW_HOTWORD = 32; // 0x20
+ field @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public static final int USAGE_CALL_ASSISTANT = 17; // 0x11
}
public static class AudioAttributes.Builder {
@@ -4198,8 +4216,11 @@ package android.media.soundtrigger {
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public android.media.soundtrigger.SoundTriggerDetector createSoundTriggerDetector(java.util.UUID, @NonNull android.media.soundtrigger.SoundTriggerDetector.Callback, @Nullable android.os.Handler);
method @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public void deleteModel(java.util.UUID);
method public int getDetectionServiceOperationsTimeout();
- method @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public android.media.soundtrigger.SoundTriggerManager.Model getModel(java.util.UUID);
+ method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public android.media.soundtrigger.SoundTriggerManager.Model getModel(java.util.UUID);
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public android.hardware.soundtrigger.SoundTrigger.ModuleProperties getModuleProperties();
+ method @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public int getParameter(@NonNull java.util.UUID, int) throws java.lang.IllegalArgumentException, java.lang.UnsupportedOperationException;
+ method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public android.hardware.soundtrigger.SoundTrigger.ModelParamRange queryParameter(@Nullable java.util.UUID, int);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public int setParameter(@Nullable java.util.UUID, int, int) throws java.lang.IllegalArgumentException, java.lang.UnsupportedOperationException;
method @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public void updateModel(android.media.soundtrigger.SoundTriggerManager.Model);
}
@@ -4356,6 +4377,7 @@ package android.media.tv {
method @Nullable public String onHardwareRemoved(android.media.tv.TvInputHardwareInfo);
method @Nullable public android.media.tv.TvInputInfo onHdmiDeviceAdded(android.hardware.hdmi.HdmiDeviceInfo);
method @Nullable public String onHdmiDeviceRemoved(android.hardware.hdmi.HdmiDeviceInfo);
+ method public void onHdmiDeviceUpdated(@NonNull android.hardware.hdmi.HdmiDeviceInfo);
}
public abstract static class TvInputService.RecordingSession {
@@ -5660,10 +5682,10 @@ package android.net.wifi {
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void registerTrafficStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.TrafficStateCallback);
method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public void removeOnWifiUsabilityStatsListener(@NonNull android.net.wifi.WifiManager.OnWifiUsabilityStatsListener);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void restoreBackupData(@NonNull byte[]);
- method @Nullable @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void restoreSoftApBackupData(@NonNull byte[]);
+ method @Nullable @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public android.net.wifi.SoftApConfiguration restoreSoftApBackupData(@NonNull byte[]);
method @Deprecated @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void restoreSupplicantBackupData(@NonNull byte[], @NonNull byte[]);
method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public byte[] retrieveBackupData();
- method @Nullable @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public byte[] retrieveSoftApBackupData();
+ method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public byte[] retrieveSoftApBackupData();
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void save(@NonNull android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiManager.ActionListener);
method @RequiresPermission(android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE) public void setDeviceMobilityState(int);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public boolean setSoftApConfiguration(@NonNull android.net.wifi.SoftApConfiguration);
@@ -6203,6 +6225,27 @@ package android.os {
method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void noteWifiScanStoppedFromSource(@NonNull android.os.WorkSource);
method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void noteWifiState(int, @Nullable String);
method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void noteWifiSupplicantStateChanged(int, boolean);
+ field public static final int WIFI_STATE_OFF = 0; // 0x0
+ field public static final int WIFI_STATE_OFF_SCANNING = 1; // 0x1
+ field public static final int WIFI_STATE_ON_CONNECTED_P2P = 5; // 0x5
+ field public static final int WIFI_STATE_ON_CONNECTED_STA = 4; // 0x4
+ field public static final int WIFI_STATE_ON_CONNECTED_STA_P2P = 6; // 0x6
+ field public static final int WIFI_STATE_ON_DISCONNECTED = 3; // 0x3
+ field public static final int WIFI_STATE_ON_NO_NETWORKS = 2; // 0x2
+ field public static final int WIFI_STATE_SOFT_AP = 7; // 0x7
+ field public static final int WIFI_SUPPL_STATE_ASSOCIATED = 7; // 0x7
+ field public static final int WIFI_SUPPL_STATE_ASSOCIATING = 6; // 0x6
+ field public static final int WIFI_SUPPL_STATE_AUTHENTICATING = 5; // 0x5
+ field public static final int WIFI_SUPPL_STATE_COMPLETED = 10; // 0xa
+ field public static final int WIFI_SUPPL_STATE_DISCONNECTED = 1; // 0x1
+ field public static final int WIFI_SUPPL_STATE_DORMANT = 11; // 0xb
+ field public static final int WIFI_SUPPL_STATE_FOUR_WAY_HANDSHAKE = 8; // 0x8
+ field public static final int WIFI_SUPPL_STATE_GROUP_HANDSHAKE = 9; // 0x9
+ field public static final int WIFI_SUPPL_STATE_INACTIVE = 3; // 0x3
+ field public static final int WIFI_SUPPL_STATE_INTERFACE_DISABLED = 2; // 0x2
+ field public static final int WIFI_SUPPL_STATE_INVALID = 0; // 0x0
+ field public static final int WIFI_SUPPL_STATE_SCANNING = 4; // 0x4
+ field public static final int WIFI_SUPPL_STATE_UNINITIALIZED = 12; // 0xc
}
public class Binder implements android.os.IBinder {
@@ -6885,7 +6928,7 @@ package android.permission {
method @BinderThread public abstract void onRevokeRuntimePermissions(@NonNull java.util.Map<java.lang.String,java.util.List<java.lang.String>>, boolean, int, @NonNull String, @NonNull java.util.function.Consumer<java.util.Map<java.lang.String,java.util.List<java.lang.String>>>);
method @BinderThread public abstract void onSetRuntimePermissionGrantStateByDeviceAdmin(@NonNull String, @NonNull String, @NonNull String, int, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @BinderThread public void onStageAndApplyRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.InputStream, @NonNull Runnable);
- method @BinderThread public void onUpdateUserSensitive();
+ method @BinderThread public void onUpdateUserSensitivePermissionFlags();
field public static final String SERVICE_INTERFACE = "android.permission.PermissionControllerService";
}
@@ -7059,7 +7102,7 @@ package android.provider {
method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static String getString(@NonNull String, @NonNull String, @Nullable String);
method public static void removeOnPropertiesChangedListener(@NonNull android.provider.DeviceConfig.OnPropertiesChangedListener);
method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static void resetToDefaults(int, @Nullable String);
- method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setProperties(@NonNull android.provider.DeviceConfig.Properties);
+ method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setProperties(@NonNull android.provider.DeviceConfig.Properties) throws android.provider.DeviceConfig.BadConfigException;
method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setProperty(@NonNull String, @NonNull String, @Nullable String, boolean);
field public static final String NAMESPACE_ACTIVITY_MANAGER = "activity_manager";
field public static final String NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT = "activity_manager_native_boot";
@@ -7091,6 +7134,10 @@ package android.provider {
field public static final String NAMESPACE_TEXTCLASSIFIER = "textclassifier";
}
+ public static class DeviceConfig.BadConfigException extends java.lang.Exception {
+ ctor public DeviceConfig.BadConfigException();
+ }
+
public static interface DeviceConfig.OnPropertiesChangedListener {
method public void onPropertiesChanged(@NonNull android.provider.DeviceConfig.Properties);
}
@@ -7105,6 +7152,16 @@ package android.provider {
method @Nullable public String getString(@NonNull String, @Nullable String);
}
+ public static final class DeviceConfig.Properties.Builder {
+ ctor public DeviceConfig.Properties.Builder(@NonNull String);
+ method @NonNull public android.provider.DeviceConfig.Properties build();
+ method @NonNull public android.provider.DeviceConfig.Properties.Builder setBoolean(@NonNull String, boolean);
+ method @NonNull public android.provider.DeviceConfig.Properties.Builder setFloat(@NonNull String, float);
+ method @NonNull public android.provider.DeviceConfig.Properties.Builder setInt(@NonNull String, int);
+ method @NonNull public android.provider.DeviceConfig.Properties.Builder setLong(@NonNull String, long);
+ method @NonNull public android.provider.DeviceConfig.Properties.Builder setString(@NonNull String, @Nullable String);
+ }
+
public final class DocumentsContract {
method public static boolean isManageMode(@NonNull android.net.Uri);
method @NonNull public static android.net.Uri setManageMode(@NonNull android.net.Uri);
@@ -9481,6 +9538,7 @@ package android.telephony {
}
public class SubscriptionInfo implements android.os.Parcelable {
+ method public boolean areUiccApplicationsEnabled();
method @Nullable public java.util.List<android.telephony.UiccAccessRule> getAccessRules();
method public int getProfileClass();
method public boolean isGroupDisabled();
@@ -9559,6 +9617,7 @@ package android.telephony {
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int);
method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent);
method public java.util.List<java.lang.String> getCarrierPackageNamesForIntentAndPhone(android.content.Intent, int);
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCarrierPrivilegeStatus(int);
method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<java.lang.String> getCarrierPrivilegedPackagesForAllActiveSubscriptions();
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.CarrierRestrictionRules getCarrierRestrictionRules();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMdn();
@@ -9600,6 +9659,7 @@ package android.telephony {
method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannelBySlot(int, @Nullable String, int);
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String iccTransmitApduBasicChannelBySlot(int, int, int, int, int, int, @Nullable String);
method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String iccTransmitApduLogicalChannelBySlot(int, int, int, int, int, int, int, @Nullable String);
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAnyRadioPoweredOn();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApplicationOnUicc(int);
method public boolean isDataConnectivityPossible();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isDataEnabledForApn(int);
@@ -9638,6 +9698,7 @@ package android.telephony {
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setSimPowerStateForSlot(int, int);
method @Deprecated public void setVisualVoicemailEnabled(android.telecom.PhoneAccountHandle, boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoiceActivationState(int);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void shutdownAllRadios();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean supplyPin(String);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int[] supplyPinReportResult(String);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean supplyPuk(String, String);
diff --git a/api/test-current.txt b/api/test-current.txt
index efb85387a743..8dcc09590ddb 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -722,6 +722,7 @@ package android.content {
public class Intent implements java.lang.Cloneable android.os.Parcelable {
field @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public static final String ACTION_MANAGE_DEFAULT_APP = "android.intent.action.MANAGE_DEFAULT_APP";
field public static final String ACTION_ROLLBACK_COMMITTED = "android.intent.action.ROLLBACK_COMMITTED";
+ field public static final String EXTRA_ORIGINATING_UID = "android.intent.extra.ORIGINATING_UID";
field public static final String EXTRA_ROLE_NAME = "android.intent.extra.ROLE_NAME";
}
@@ -753,6 +754,7 @@ package android.content.pm {
method public void setEnableRollback(boolean);
method @RequiresPermission("android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS") public void setGrantedRuntimePermissions(String[]);
method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setInstallAsApex();
+ method public void setInstallerPackageName(@Nullable String);
method public void setRequestDowngrade(boolean);
method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setStaged();
}
@@ -2452,6 +2454,16 @@ package android.provider {
method @Nullable public String getString(@NonNull String, @Nullable String);
}
+ public static final class DeviceConfig.Properties.Builder {
+ ctor public DeviceConfig.Properties.Builder(@NonNull String);
+ method @NonNull public android.provider.DeviceConfig.Properties build();
+ method @NonNull public android.provider.DeviceConfig.Properties.Builder setBoolean(@NonNull String, boolean);
+ method @NonNull public android.provider.DeviceConfig.Properties.Builder setFloat(@NonNull String, float);
+ method @NonNull public android.provider.DeviceConfig.Properties.Builder setInt(@NonNull String, int);
+ method @NonNull public android.provider.DeviceConfig.Properties.Builder setLong(@NonNull String, long);
+ method @NonNull public android.provider.DeviceConfig.Properties.Builder setString(@NonNull String, @Nullable String);
+ }
+
public final class MediaStore {
method @RequiresPermission(android.Manifest.permission.CLEAR_APP_USER_DATA) public static void deleteContributedMedia(android.content.Context, String, android.os.UserHandle) throws java.io.IOException;
method @RequiresPermission(android.Manifest.permission.CLEAR_APP_USER_DATA) public static long getContributedMediaSize(android.content.Context, String, android.os.UserHandle) throws java.io.IOException;
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 3c5ad4231133..4d38ba03b1df 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -272,7 +272,7 @@ status_t StatsService::onTransact(uint32_t code, const Parcel& data, Parcel* rep
}
return NO_ERROR;
}
- default: { return BnStatsManager::onTransact(code, data, reply, flags); }
+ default: { return BnStatsd::onTransact(code, data, reply, flags); }
}
}
@@ -862,13 +862,13 @@ status_t StatsService::cmd_log_binary_push(int out, const Vector<String8>& args)
int64_t trainVersion = strtoll(args[2].c_str(), nullptr, 10);
int options = 0;
if (args[3] == "1") {
- options = options | IStatsManager::FLAG_REQUIRE_STAGING;
+ options = options | IStatsd::FLAG_REQUIRE_STAGING;
}
if (args[4] == "1") {
- options = options | IStatsManager::FLAG_ROLLBACK_ENABLED;
+ options = options | IStatsd::FLAG_ROLLBACK_ENABLED;
}
if (args[5] == "1") {
- options = options | IStatsManager::FLAG_REQUIRE_LOW_LATENCY_MONITOR;
+ options = options | IStatsd::FLAG_REQUIRE_LOW_LATENCY_MONITOR;
}
int32_t state = atoi(args[6].c_str());
vector<int64_t> experimentIds;
@@ -1406,9 +1406,9 @@ Status StatsService::sendBinaryPushStateChangedAtom(const android::String16& tra
StorageManager::writeTrainInfo(trainVersionCode, trainNameUtf8, state, experimentIds);
userid_t userId = multiuser_get_user_id(uid);
- bool requiresStaging = options & IStatsManager::FLAG_REQUIRE_STAGING;
- bool rollbackEnabled = options & IStatsManager::FLAG_ROLLBACK_ENABLED;
- bool requiresLowLatencyMonitor = options & IStatsManager::FLAG_REQUIRE_LOW_LATENCY_MONITOR;
+ bool requiresStaging = options & IStatsd::FLAG_REQUIRE_STAGING;
+ bool rollbackEnabled = options & IStatsd::FLAG_ROLLBACK_ENABLED;
+ bool requiresLowLatencyMonitor = options & IStatsd::FLAG_REQUIRE_LOW_LATENCY_MONITOR;
LogEvent event(trainNameUtf8, trainVersionCode, requiresStaging, rollbackEnabled,
requiresLowLatencyMonitor, state, experimentIdsProtoBuffer, userId);
mProcessor->OnLogEvent(&event);
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 50b1014f4e8a..9abf415ad91f 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -29,9 +29,9 @@
#include <android/frameworks/stats/1.0/IStats.h>
#include <android/frameworks/stats/1.0/types.h>
-#include <android/os/BnStatsManager.h>
+#include <android/os/BnStatsd.h>
#include <android/os/IStatsCompanionService.h>
-#include <android/os/IStatsManager.h>
+#include <android/os/IStatsd.h>
#include <binder/IResultReceiver.h>
#include <binder/ParcelFileDescriptor.h>
#include <utils/Looper.h>
@@ -52,7 +52,7 @@ namespace statsd {
using android::hardware::Return;
-class StatsService : public BnStatsManager,
+class StatsService : public BnStatsd,
public IStats,
public IBinder::DeathRecipient {
public:
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 577272e38707..9711e06e5c16 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -7855,6 +7855,7 @@ public class Activity extends ContextThemeWrapper
mCurrentConfig = config;
mWindow.setColorMode(info.colorMode);
+ mWindow.setPreferMinimalPostProcessing(info.preferMinimalPostProcessing);
setAutofillOptions(application.getAutofillOptions());
setContentCaptureOptions(application.getContentCaptureOptions());
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 49a8e2f3f816..93b6454edcf3 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -7395,6 +7395,24 @@ public final class ActivityThread extends ClientTransactionHandler {
super.remove(path);
}
}
+
+ @Override
+ public void rename(String oldPath, String newPath) throws ErrnoException {
+ try {
+ super.rename(oldPath, newPath);
+ } catch (ErrnoException e) {
+ if (e.errno == OsConstants.EXDEV && oldPath.startsWith("/storage/")) {
+ Log.v(TAG, "Recovering failed rename " + oldPath + " to " + newPath);
+ try {
+ Files.move(new File(oldPath).toPath(), new File(newPath).toPath());
+ } catch (IOException e2) {
+ throw e;
+ }
+ } else {
+ throw e;
+ }
+ }
+ }
}
public static void main(String[] args) {
diff --git a/core/java/android/app/StatsManager.java b/core/java/android/app/StatsManager.java
index 90cd51f8649f..f6e9569f513c 100644
--- a/core/java/android/app/StatsManager.java
+++ b/core/java/android/app/StatsManager.java
@@ -27,8 +27,8 @@ import android.os.IBinder;
import android.os.IPullAtomCallback;
import android.os.IPullAtomResultReceiver;
import android.os.IStatsCompanionService;
-import android.os.IStatsManager;
import android.os.IStatsPullerCallback;
+import android.os.IStatsd;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.AndroidException;
@@ -56,7 +56,7 @@ public final class StatsManager {
private final Context mContext;
@GuardedBy("sLock")
- private IStatsManager mService;
+ private IStatsd mService;
@GuardedBy("sLock")
private IStatsCompanionService mStatsCompanion;
@@ -129,7 +129,7 @@ public final class StatsManager {
public void addConfig(long configKey, byte[] config) throws StatsUnavailableException {
synchronized (sLock) {
try {
- IStatsManager service = getIStatsManagerLocked();
+ IStatsd service = getIStatsdLocked();
// can throw IllegalArgumentException
service.addConfiguration(configKey, config, mContext.getOpPackageName());
} catch (RemoteException e) {
@@ -166,7 +166,7 @@ public final class StatsManager {
public void removeConfig(long configKey) throws StatsUnavailableException {
synchronized (sLock) {
try {
- IStatsManager service = getIStatsManagerLocked();
+ IStatsd service = getIStatsdLocked();
service.removeConfiguration(configKey, mContext.getOpPackageName());
} catch (RemoteException e) {
Slog.e(TAG, "Failed to connect to statsd when removing configuration");
@@ -227,7 +227,7 @@ public final class StatsManager {
throws StatsUnavailableException {
synchronized (sLock) {
try {
- IStatsManager service = getIStatsManagerLocked();
+ IStatsd service = getIStatsdLocked();
if (pendingIntent != null) {
// Extracts IIntentSender from the PendingIntent and turns it into an IBinder.
IBinder intentSender = pendingIntent.getTarget().asBinder();
@@ -281,7 +281,7 @@ public final class StatsManager {
throws StatsUnavailableException {
synchronized (sLock) {
try {
- IStatsManager service = getIStatsManagerLocked();
+ IStatsd service = getIStatsdLocked();
if (pendingIntent == null) {
service.removeDataFetchOperation(configKey, mContext.getOpPackageName());
} else {
@@ -319,7 +319,7 @@ public final class StatsManager {
throws StatsUnavailableException {
synchronized (sLock) {
try {
- IStatsManager service = getIStatsManagerLocked();
+ IStatsd service = getIStatsdLocked();
if (pendingIntent == null) {
service.removeActiveConfigsChangedOperation(mContext.getOpPackageName());
return new long[0];
@@ -367,7 +367,7 @@ public final class StatsManager {
public byte[] getReports(long configKey) throws StatsUnavailableException {
synchronized (sLock) {
try {
- IStatsManager service = getIStatsManagerLocked();
+ IStatsd service = getIStatsdLocked();
return service.getData(configKey, mContext.getOpPackageName());
} catch (RemoteException e) {
Slog.e(TAG, "Failed to connect to statsd when getting data");
@@ -404,7 +404,7 @@ public final class StatsManager {
public byte[] getStatsMetadata() throws StatsUnavailableException {
synchronized (sLock) {
try {
- IStatsManager service = getIStatsManagerLocked();
+ IStatsd service = getIStatsdLocked();
return service.getMetadata(mContext.getOpPackageName());
} catch (RemoteException e) {
Slog.e(TAG, "Failed to connect to statsd when getting metadata");
@@ -439,7 +439,7 @@ public final class StatsManager {
throws StatsUnavailableException {
synchronized (sLock) {
try {
- IStatsManager service = getIStatsManagerLocked();
+ IStatsd service = getIStatsdLocked();
if (service == null) {
if (DEBUG) {
Slog.d(TAG, "Failed to find statsd when getting experiment IDs");
@@ -476,7 +476,7 @@ public final class StatsManager {
throws StatsUnavailableException {
synchronized (sLock) {
try {
- IStatsManager service = getIStatsManagerLocked();
+ IStatsd service = getIStatsdLocked();
if (callback == null) {
service.unregisterPullerCallback(atomTag, mContext.getOpPackageName());
} else {
@@ -660,11 +660,11 @@ public final class StatsManager {
}
@GuardedBy("sLock")
- private IStatsManager getIStatsManagerLocked() throws StatsUnavailableException {
+ private IStatsd getIStatsdLocked() throws StatsUnavailableException {
if (mService != null) {
return mService;
}
- mService = IStatsManager.Stub.asInterface(ServiceManager.getService("stats"));
+ mService = IStatsd.Stub.asInterface(ServiceManager.getService("stats"));
if (mService == null) {
throw new StatsUnavailableException("could not be found");
}
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 601b65863db1..dd54d7ccf826 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -53,7 +53,9 @@ import android.content.RestrictionsManager;
import android.content.om.IOverlayManager;
import android.content.om.OverlayManager;
import android.content.pm.CrossProfileApps;
+import android.content.pm.DataLoaderManager;
import android.content.pm.ICrossProfileApps;
+import android.content.pm.IDataLoaderManager;
import android.content.pm.IPackageManager;
import android.content.pm.IShortcutService;
import android.content.pm.LauncherApps;
@@ -1197,6 +1199,15 @@ public final class SystemServiceRegistry {
return new BatteryStatsManager(
IBatteryStats.Stub.asInterface(b));
}});
+ registerService(Context.DATA_LOADER_MANAGER_SERVICE, DataLoaderManager.class,
+ new CachedServiceFetcher<DataLoaderManager>() {
+ @Override
+ public DataLoaderManager createService(ContextImpl ctx)
+ throws ServiceNotFoundException {
+ IBinder b = ServiceManager.getServiceOrThrow(
+ Context.DATA_LOADER_MANAGER_SERVICE);
+ return new DataLoaderManager(IDataLoaderManager.Stub.asInterface(b));
+ }});
//CHECKSTYLE:ON IndentationCheck
sInitializing = true;
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 915e4572c035..63eb7ceae8b2 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -11085,6 +11085,53 @@ public class DevicePolicyManager {
}
/**
+ * Sets the set of package names that are allowed to request user consent for cross-profile
+ * communication.
+ *
+ * <p>Assumes that the caller is a profile owner and is the given {@code admin}.
+ *
+ * <p>Previous calls are overridden by each subsequent call to this method.
+ *
+ * @param admin the {@link DeviceAdminReceiver} this request is associated with
+ * @param packageNames the new cross-profile package names
+ */
+ public void setCrossProfilePackages(
+ @NonNull ComponentName admin, @NonNull Set<String> packageNames) {
+ throwIfParentInstance("setCrossProfilePackages");
+ if (mService != null) {
+ try {
+ mService.setCrossProfilePackages(admin, new ArrayList<>(packageNames));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
+ * Returns the set of package names that the admin has previously set as allowed to request user
+ * consent for cross-profile communication, via {@link
+ * #setCrossProfilePackages(ComponentName, Set)}.
+ *
+ * <p>Assumes that the caller is a profile owner and is the given {@code admin}.
+ *
+ * @param admin the {@link DeviceAdminReceiver} this request is associated with
+ * @return the set of package names the admin has previously set as allowed to request user
+ * consent for cross-profile communication, via {@link
+ * #setCrossProfilePackages(ComponentName, Set)}
+ */
+ public @NonNull Set<String> getCrossProfilePackages(@NonNull ComponentName admin) {
+ throwIfParentInstance("getCrossProfilePackages");
+ if (mService != null) {
+ try {
+ return new ArraySet<>(mService.getCrossProfilePackages(admin));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return Collections.emptySet();
+ }
+
+ /**
* Returns whether the device is being used as a managed kiosk. These requirements are as
* follows:
* <ul>
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 34246fa808bd..ff1ecd558400 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -438,6 +438,9 @@ interface IDevicePolicyManager {
boolean isPackageAllowedToAccessCalendarForUser(String packageName, int userHandle);
List<String> getCrossProfileCalendarPackagesForUser(int userHandle);
+ void setCrossProfilePackages(in ComponentName admin, in List<String> packageNames);
+ List<String> getCrossProfilePackages(in ComponentName admin);
+
boolean isManagedKiosk();
boolean isUnattendedManagedKiosk();
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 49187dcde342..323c7d172033 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -17,6 +17,7 @@
package android.bluetooth;
import android.Manifest;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -33,8 +34,12 @@ import android.os.Process;
import android.os.RemoteException;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.io.IOException;
import java.io.UnsupportedEncodingException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.UUID;
/**
@@ -771,6 +776,13 @@ public final class BluetoothDevice implements Parcelable {
@UnsupportedAppUsage
public static final String EXTRA_SDP_SEARCH_STATUS =
"android.bluetooth.device.extra.SDP_SEARCH_STATUS";
+
+ /** @hide */
+ @IntDef(prefix = "ACCESS_", value = {ACCESS_UNKNOWN,
+ ACCESS_ALLOWED, ACCESS_REJECTED})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AccessPermission{}
+
/**
* For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission},
* {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}.
@@ -1096,15 +1108,14 @@ public final class BluetoothDevice implements Parcelable {
/**
* Get the most recent identified battery level of this Bluetooth device
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
*
* @return Battery level in percents from 0 to 100, or {@link #BATTERY_LEVEL_UNKNOWN} if
* Bluetooth is disabled, or device is disconnected, or does not have any battery reporting
* service, or return value is invalid
* @hide
*/
+ @SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH)
- @UnsupportedAppUsage
public int getBatteryLevel() {
final IBluetooth service = sService;
if (service == null) {
@@ -1187,8 +1198,15 @@ public final class BluetoothDevice implements Parcelable {
return false;
}
- /** @hide */
- @UnsupportedAppUsage
+ /**
+ * Gets whether bonding was initiated locally
+ *
+ * @return true if bonding is initiated locally, false otherwise
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.BLUETOOTH)
public boolean isBondingInitiatedLocally() {
final IBluetooth service = sService;
if (service == null) {
@@ -1480,15 +1498,20 @@ public final class BluetoothDevice implements Parcelable {
return false;
}
- /** @hide */
- @UnsupportedAppUsage
- public boolean setPasskey(int passkey) {
- //TODO(BT)
- /*
- try {
- return sService.setPasskey(this, true, 4, passkey);
- } catch (RemoteException e) {Log.e(TAG, "", e);}*/
- return false;
+ /**
+ * Set the pin during pairing when the pairing method is {@link #PAIRING_VARIANT_PIN}
+ *
+ * @return true pin has been set false for error
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ public boolean setPin(@Nullable String pin) {
+ byte[] pinBytes = convertPinToBytes(pin);
+ if (pinBytes == null) {
+ return false;
+ }
+ return setPin(pinBytes);
}
/**
@@ -1511,22 +1534,18 @@ public final class BluetoothDevice implements Parcelable {
return false;
}
- /** @hide */
- public boolean setRemoteOutOfBandData() {
- // TODO(BT)
- /*
- try {
- return sService.setRemoteOutOfBandData(this);
- } catch (RemoteException e) {Log.e(TAG, "", e);}*/
- return false;
- }
-
- /** @hide */
- @UnsupportedAppUsage
- public boolean cancelPairingUserInput() {
+ /**
+ * Cancels pairing to this device
+ *
+ * @return true if pairing cancelled successfully, false otherwise
+ *
+ * @hide
+ */
+ @SystemApi
+ public boolean cancelPairing() {
final IBluetooth service = sService;
if (service == null) {
- Log.e(TAG, "BT not enabled. Cannot create pairing user input");
+ Log.e(TAG, "BT not enabled. Cannot cancel pairing");
return false;
}
try {
@@ -1537,17 +1556,6 @@ public final class BluetoothDevice implements Parcelable {
return false;
}
- /** @hide */
- @UnsupportedAppUsage
- public boolean isBluetoothDock() {
- // TODO(BT)
- /*
- try {
- return sService.isBluetoothDock(this);
- } catch (RemoteException e) {Log.e(TAG, "", e);}*/
- return false;
- }
-
boolean isBluetoothEnabled() {
boolean ret = false;
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
@@ -1558,13 +1566,14 @@ public final class BluetoothDevice implements Parcelable {
}
/**
- * Requires {@link android.Manifest.permission#BLUETOOTH}.
+ * Gets whether the phonebook access is allowed for this bluetooth device
*
* @return Whether the phonebook access is allowed to this device. Can be {@link
* #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}.
* @hide
*/
- @UnsupportedAppUsage
+ @SystemApi
+ @RequiresPermission(Manifest.permission.BLUETOOTH)
public int getPhonebookAccessPermission() {
final IBluetooth service = sService;
if (service == null) {
@@ -1667,14 +1676,14 @@ public final class BluetoothDevice implements Parcelable {
}
/**
- * Requires {@link android.Manifest.permission#BLUETOOTH}.
+ * Gets whether message access is allowed to this bluetooth device
*
- * @return Whether the message access is allowed to this device. Can be {@link #ACCESS_UNKNOWN},
- * {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}.
+ * @return Whether the message access is allowed to this device.
* @hide
*/
- @UnsupportedAppUsage
- public int getMessageAccessPermission() {
+ @SystemApi
+ @RequiresPermission(Manifest.permission.BLUETOOTH)
+ public @AccessPermission int getMessageAccessPermission() {
final IBluetooth service = sService;
if (service == null) {
return ACCESS_UNKNOWN;
@@ -1689,15 +1698,18 @@ public final class BluetoothDevice implements Parcelable {
/**
* Sets whether the message access is allowed to this device.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
*
- * @param value Can be {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link
- * #ACCESS_REJECTED}.
+ * @param value is the value we are setting the message access permission to
* @return Whether the value has been successfully set.
* @hide
*/
- @UnsupportedAppUsage
- public boolean setMessageAccessPermission(int value) {
+ @SystemApi
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public boolean setMessageAccessPermission(@AccessPermission int value) {
+ // Validates param value is one of the accepted constants
+ if (value != ACCESS_ALLOWED && value != ACCESS_REJECTED && value != ACCESS_UNKNOWN) {
+ throw new IllegalArgumentException(value + "is not a valid AccessPermission value");
+ }
final IBluetooth service = sService;
if (service == null) {
return false;
@@ -1711,13 +1723,14 @@ public final class BluetoothDevice implements Parcelable {
}
/**
- * Requires {@link android.Manifest.permission#BLUETOOTH}.
+ * Gets whether sim access is allowed for this bluetooth device
*
- * @return Whether the Sim access is allowed to this device. Can be {@link #ACCESS_UNKNOWN},
- * {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}.
+ * @return Whether the Sim access is allowed to this device.
* @hide
*/
- public int getSimAccessPermission() {
+ @SystemApi
+ @RequiresPermission(Manifest.permission.BLUETOOTH)
+ public @AccessPermission int getSimAccessPermission() {
final IBluetooth service = sService;
if (service == null) {
return ACCESS_UNKNOWN;
@@ -1732,14 +1745,14 @@ public final class BluetoothDevice implements Parcelable {
/**
* Sets whether the Sim access is allowed to this device.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
*
* @param value Can be {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link
* #ACCESS_REJECTED}.
* @return Whether the value has been successfully set.
* @hide
*/
- @UnsupportedAppUsage
+ @SystemApi
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
public boolean setSimAccessPermission(int value) {
final IBluetooth service = sService;
if (service == null) {
@@ -1970,7 +1983,7 @@ public final class BluetoothDevice implements Parcelable {
* @return the pin code as a UTF-8 byte array, or null if it is an invalid Bluetooth pin.
* @hide
*/
- @UnsupportedAppUsage
+ @VisibleForTesting
public static byte[] convertPinToBytes(String pin) {
if (pin == null) {
return null;
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index ca2de6a8d1e4..47fb3759f224 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1728,6 +1728,7 @@ public class Intent implements Parcelable, Cloneable {
* @hide
*/
@SystemApi
+ @TestApi
public static final String EXTRA_ORIGINATING_UID
= "android.intent.extra.ORIGINATING_UID";
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 26193f6ebb3d..fe59f05dabfc 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -290,6 +290,34 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
public int colorMode = COLOR_MODE_DEFAULT;
/**
+ * Indicates whether the activity wants the connected display to do minimal post processing on
+ * the produced image or video frames. This will only be requested if this activity's main
+ * window is visible on the screen.
+ *
+ * <p>This setting should be used when low latency has a higher priority than image enhancement
+ * processing (e.g. for games or video conferencing).
+ *
+ * <p>If the Display sink is connected via HDMI, the device will begin to send infoframes with
+ * Auto Low Latency Mode enabled and Game Content Type. This will switch the connected display
+ * to a minimal image processing mode (if available), which reduces latency, improving the user
+ * experience for gaming or video conferencing applications. For more information, see HDMI 2.1
+ * specification.
+ *
+ * <p>If the Display sink has an internal connection or uses some other protocol than HDMI,
+ * effects may be similar but implementation-defined.
+ *
+ * <p>The ability to switch to a mode with minimal post proessing may be disabled by a user
+ * setting in the system settings menu. In that case, this field is ignored and the display will
+ * remain in its current mode.
+ *
+ * <p>Set from attribute {@link android.R.attr#preferMinimalPostProcessing}.
+ *
+ * @see android.view.WindowManager.LayoutParams#preferMinimalPostProcessing
+ * @see android.view.Display#isMinimalPostProcessingSupported
+ */
+ public boolean preferMinimalPostProcessing = false;
+
+ /**
* Bit in {@link #flags} indicating whether this activity is able to
* run in multiple processes. If
* true, the system may instantiate it in the some process as the
@@ -1004,6 +1032,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
requestedVrComponent = orig.requestedVrComponent;
rotationAnimation = orig.rotationAnimation;
colorMode = orig.colorMode;
+ preferMinimalPostProcessing = orig.preferMinimalPostProcessing;
maxAspectRatio = orig.maxAspectRatio;
minAspectRatio = orig.minAspectRatio;
}
@@ -1231,6 +1260,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
dest.writeInt(colorMode);
dest.writeFloat(maxAspectRatio);
dest.writeFloat(minAspectRatio);
+ dest.writeBoolean(preferMinimalPostProcessing);
}
/**
@@ -1349,6 +1379,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
colorMode = source.readInt();
maxAspectRatio = source.readFloat();
minAspectRatio = source.readFloat();
+ preferMinimalPostProcessing = source.readBoolean();
}
/**
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index f017aad25c0c..8f5143518cbe 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1770,7 +1770,8 @@ public class PackageInstaller {
* @param installerPackageName name of the installer package
* {@hide}
*/
- public void setInstallerPackageName(String installerPackageName) {
+ @TestApi
+ public void setInstallerPackageName(@Nullable String installerPackageName) {
this.installerPackageName = installerPackageName;
}
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index c9551378c190..df2d0dd8992e 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -24,7 +24,6 @@ import android.util.IntArray;
import android.util.SparseArray;
import android.view.Display;
import android.view.DisplayInfo;
-import android.view.Surface;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
@@ -151,11 +150,14 @@ public abstract class DisplayManagerInternal {
* has a preference.
* @param requestedModeId The preferred mode id for the top-most visible window that has a
* preference.
+ * @param preferMinimalPostProcessing Whether there is a visible window on the screen that wants
+ * minimal post processing.
* @param inTraversal True if called from WindowManagerService during a window traversal
* prior to call to performTraversalInTransactionFromWindowManager.
*/
public abstract void setDisplayProperties(int displayId, boolean hasContent,
- float requestedRefreshRate, int requestedModeId, boolean inTraversal);
+ float requestedRefreshRate, int requestedModeId, boolean preferMinimalPostProcessing,
+ boolean inTraversal);
/**
* Applies an offset to the contents of a display, for example to avoid burn-in.
diff --git a/core/java/android/hardware/soundtrigger/ModelParams.aidl b/core/java/android/hardware/soundtrigger/ModelParams.aidl
new file mode 100644
index 000000000000..d90dc811fc32
--- /dev/null
+++ b/core/java/android/hardware/soundtrigger/ModelParams.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2019 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 android.hardware.soundtrigger;
+
+/**
+ * Model specific parameters to be used with parameter set and get APIs
+ * {@hide}
+ */
+@Backing(type="int")
+enum ModelParams {
+ /**
+ * Placeholder for invalid model parameter used for returning error or
+ * passing an invalid value.
+ */
+ INVALID = -1,
+ /**
+ * Controls the sensitivity threshold adjustment factor for a given model.
+ * Negative value corresponds to less sensitive model (high threshold) and
+ * a positive value corresponds to a more sensitive model (low threshold).
+ * Default value is 0.
+ */
+ THRESHOLD_FACTOR = 0,
+}
diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.aidl b/core/java/android/hardware/soundtrigger/SoundTrigger.aidl
index 325a9addc8ff..94c4216227bc 100644
--- a/core/java/android/hardware/soundtrigger/SoundTrigger.aidl
+++ b/core/java/android/hardware/soundtrigger/SoundTrigger.aidl
@@ -24,5 +24,6 @@ parcelable SoundTrigger.GenericRecognitionEvent;
parcelable SoundTrigger.KeyphraseRecognitionExtra;
parcelable SoundTrigger.KeyphraseSoundModel;
parcelable SoundTrigger.GenericSoundModel;
+parcelable SoundTrigger.ModelParamRange;
parcelable SoundTrigger.ModuleProperties;
parcelable SoundTrigger.RecognitionConfig;
diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.java b/core/java/android/hardware/soundtrigger/SoundTrigger.java
index b1134e120df2..86f3eec4109e 100644
--- a/core/java/android/hardware/soundtrigger/SoundTrigger.java
+++ b/core/java/android/hardware/soundtrigger/SoundTrigger.java
@@ -567,6 +567,65 @@ public class SoundTrigger {
}
}
+ /*****************************************************************************
+ * A ModelParamRange is a representation of supported parameter range for a
+ * given loaded model.
+ ****************************************************************************/
+ public static final class ModelParamRange implements Parcelable {
+
+ /**
+ * start of supported range inclusive
+ */
+ public final int start;
+
+ /**
+ * end of supported range inclusive
+ */
+ public final int end;
+
+ ModelParamRange(int start, int end) {
+ this.start = start;
+ this.end = end;
+ }
+
+ private ModelParamRange(@NonNull Parcel in) {
+ this.start = in.readInt();
+ this.end = in.readInt();
+ }
+
+ @NonNull
+ public static final Creator<ModelParamRange> CREATOR = new Creator<ModelParamRange>() {
+ @Override
+ @NonNull
+ public ModelParamRange createFromParcel(@NonNull Parcel in) {
+ return new ModelParamRange(in);
+ }
+
+ @Override
+ @NonNull
+ public ModelParamRange[] newArray(int size) {
+ return new ModelParamRange[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(start);
+ dest.writeInt(end);
+ }
+
+ @Override
+ @NonNull
+ public String toString() {
+ return "ModelParamRange [start=" + start + ", end=" + end + "]";
+ }
+ }
+
/**
* Modes for key phrase recognition
*/
diff --git a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
index 911354862ff4..b16ef5c43346 100644
--- a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
+++ b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
@@ -16,7 +16,9 @@
package android.hardware.soundtrigger;
+import android.annotation.Nullable;
import android.annotation.UnsupportedAppUsage;
+import android.hardware.soundtrigger.SoundTrigger.ModelParamRange;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -150,6 +152,57 @@ public class SoundTriggerModule {
*/
public native int getModelState(int soundModelHandle);
+ /**
+ * Set a model specific {@link ModelParams} with the given value. This
+ * parameter will keep its value for the duration the model is loaded regardless of starting and
+ * stopping recognition. Once the model is unloaded, the value will be lost.
+ * {@link SoundTriggerModule#isParameterSupported} should be checked first before calling this
+ * method.
+ *
+ * @param soundModelHandle handle of model to apply parameter
+ * @param modelParam {@link ModelParams}
+ * @param value Value to set
+ * @return - {@link SoundTrigger#STATUS_OK} in case of success
+ * - {@link SoundTrigger#STATUS_NO_INIT} if the native service cannot be reached
+ * - {@link SoundTrigger#STATUS_BAD_VALUE} invalid input parameter
+ * - {@link SoundTrigger#STATUS_INVALID_OPERATION} if the call is out of sequence or
+ * if API is not supported by HAL
+ */
+ public native int setParameter(int soundModelHandle,
+ @ModelParams int modelParam, int value);
+
+ /**
+ * Get a model specific {@link ModelParams}. This parameter will keep its value
+ * for the duration the model is loaded regardless of starting and stopping recognition.
+ * Once the model is unloaded, the value will be lost. If the value is not set, a default
+ * value is returned. See {@link ModelParams} for parameter default values.
+ * {@link SoundTriggerModule#isParameterSupported} should be checked first before
+ * calling this method. Otherwise, an exception can be thrown.
+ *
+ * @param soundModelHandle handle of model to get parameter
+ * @param modelParam {@link ModelParams}
+ * @return value of parameter
+ * @throws UnsupportedOperationException if hal or model do not support this API.
+ * {@link SoundTriggerModule#isParameterSupported} should be checked first.
+ * @throws IllegalArgumentException if invalid model handle or parameter is passed.
+ * {@link SoundTriggerModule#isParameterSupported} should be checked first.
+ */
+ public native int getParameter(int soundModelHandle,
+ @ModelParams int modelParam)
+ throws UnsupportedOperationException, IllegalArgumentException;
+
+ /**
+ * Determine if parameter control is supported for the given model handle.
+ * This method should be checked prior to calling {@link SoundTriggerModule#setParameter} or
+ * {@link SoundTriggerModule#getParameter}.
+ *
+ * @param soundModelHandle handle of model to get parameter
+ * @param modelParam {@link ModelParams}
+ * @return supported range of parameter, null if not supported
+ */
+ @Nullable
+ public native ModelParamRange queryParameter(int soundModelHandle, @ModelParams int modelParam);
+
private class NativeEventHandlerDelegate {
private final Handler mHandler;
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 9fed26916899..53ea936ea972 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -17,6 +17,8 @@
package android.os;
import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP;
+import static android.os.BatteryStatsManager.NUM_WIFI_STATES;
+import static android.os.BatteryStatsManager.NUM_WIFI_SUPPL_STATES;
import android.annotation.IntDef;
import android.annotation.UnsupportedAppUsage;
@@ -24,6 +26,8 @@ import android.app.ActivityManager;
import android.app.job.JobParameters;
import android.content.Context;
import android.content.pm.ApplicationInfo;
+import android.os.BatteryStatsManager.WifiState;
+import android.os.BatteryStatsManager.WifiSupplState;
import android.server.ServerProtoEnums;
import android.service.batterystats.BatteryStatsServiceDumpHistoryProto;
import android.service.batterystats.BatteryStatsServiceDumpProto;
@@ -2422,7 +2426,7 @@ public abstract class BatteryStats implements Parcelable {
public static final int DATA_CONNECTION_OUT_OF_SERVICE = 0;
public static final int DATA_CONNECTION_EMERGENCY_SERVICE =
- TelephonyManager.MAX_NETWORK_TYPE + 1;
+ TelephonyManager.getAllNetworkTypes().length + 1;
public static final int DATA_CONNECTION_OTHER = DATA_CONNECTION_EMERGENCY_SERVICE + 1;
@@ -2458,41 +2462,6 @@ public abstract class BatteryStats implements Parcelable {
*/
public abstract Timer getPhoneDataConnectionTimer(int dataType);
- public static final int WIFI_SUPPL_STATE_INVALID = 0;
- public static final int WIFI_SUPPL_STATE_DISCONNECTED = 1;
- public static final int WIFI_SUPPL_STATE_INTERFACE_DISABLED = 2;
- public static final int WIFI_SUPPL_STATE_INACTIVE = 3;
- public static final int WIFI_SUPPL_STATE_SCANNING = 4;
- public static final int WIFI_SUPPL_STATE_AUTHENTICATING = 5;
- public static final int WIFI_SUPPL_STATE_ASSOCIATING = 6;
- public static final int WIFI_SUPPL_STATE_ASSOCIATED = 7;
- public static final int WIFI_SUPPL_STATE_FOUR_WAY_HANDSHAKE = 8;
- public static final int WIFI_SUPPL_STATE_GROUP_HANDSHAKE = 9;
- public static final int WIFI_SUPPL_STATE_COMPLETED = 10;
- public static final int WIFI_SUPPL_STATE_DORMANT = 11;
- public static final int WIFI_SUPPL_STATE_UNINITIALIZED = 12;
-
- public static final int NUM_WIFI_SUPPL_STATES = WIFI_SUPPL_STATE_UNINITIALIZED+1;
-
- /** @hide */
- @IntDef(flag = true, prefix = { "WIFI_SUPPL_STATE_" }, value = {
- WIFI_SUPPL_STATE_INVALID,
- WIFI_SUPPL_STATE_DISCONNECTED,
- WIFI_SUPPL_STATE_INTERFACE_DISABLED,
- WIFI_SUPPL_STATE_INACTIVE,
- WIFI_SUPPL_STATE_SCANNING,
- WIFI_SUPPL_STATE_AUTHENTICATING,
- WIFI_SUPPL_STATE_ASSOCIATING,
- WIFI_SUPPL_STATE_ASSOCIATED,
- WIFI_SUPPL_STATE_FOUR_WAY_HANDSHAKE,
- WIFI_SUPPL_STATE_GROUP_HANDSHAKE,
- WIFI_SUPPL_STATE_COMPLETED,
- WIFI_SUPPL_STATE_DORMANT,
- WIFI_SUPPL_STATE_UNINITIALIZED,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface WifiSupplState {}
-
static final String[] WIFI_SUPPL_STATE_NAMES = {
"invalid", "disconn", "disabled", "inactive", "scanning",
"authenticating", "associating", "associated", "4-way-handshake",
@@ -2635,31 +2604,6 @@ public abstract class BatteryStats implements Parcelable {
@UnsupportedAppUsage
public abstract long getGlobalWifiRunningTime(long elapsedRealtimeUs, int which);
- public static final int WIFI_STATE_OFF = 0;
- public static final int WIFI_STATE_OFF_SCANNING = 1;
- public static final int WIFI_STATE_ON_NO_NETWORKS = 2;
- public static final int WIFI_STATE_ON_DISCONNECTED = 3;
- public static final int WIFI_STATE_ON_CONNECTED_STA = 4;
- public static final int WIFI_STATE_ON_CONNECTED_P2P = 5;
- public static final int WIFI_STATE_ON_CONNECTED_STA_P2P = 6;
- public static final int WIFI_STATE_SOFT_AP = 7;
-
- public static final int NUM_WIFI_STATES = WIFI_STATE_SOFT_AP + 1;
-
- /** @hide */
- @IntDef(flag = true, prefix = { "WIFI_STATE_" }, value = {
- WIFI_STATE_OFF,
- WIFI_STATE_OFF_SCANNING,
- WIFI_STATE_ON_NO_NETWORKS,
- WIFI_STATE_ON_DISCONNECTED,
- WIFI_STATE_ON_CONNECTED_STA,
- WIFI_STATE_ON_CONNECTED_P2P,
- WIFI_STATE_ON_CONNECTED_STA_P2P,
- WIFI_STATE_SOFT_AP
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface WifiState {}
-
static final String[] WIFI_STATE_NAMES = {
"off", "scanning", "no_net", "disconn",
"sta", "p2p", "sta_p2p", "soft_ap"
diff --git a/core/java/android/os/BatteryStatsManager.java b/core/java/android/os/BatteryStatsManager.java
index e5650aea0522..0545666ca743 100644
--- a/core/java/android/os/BatteryStatsManager.java
+++ b/core/java/android/os/BatteryStatsManager.java
@@ -16,6 +16,7 @@
package android.os;
+import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -28,6 +29,9 @@ import android.os.connectivity.WifiBatteryStats;
import com.android.internal.app.IBatteryStats;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* This class provides an API surface for internal system components to report events that are
* needed for battery usage/estimation and battery blaming for apps.
@@ -39,6 +43,116 @@ import com.android.internal.app.IBatteryStats;
@SystemApi
@SystemService(Context.BATTERY_STATS_SERVICE)
public class BatteryStatsManager {
+ /**
+ * Wifi states.
+ *
+ * @see #noteWifiState(int, String)
+ */
+ /**
+ * Wifi fully off.
+ */
+ public static final int WIFI_STATE_OFF = 0;
+ /**
+ * Wifi connectivity off, but scanning enabled.
+ */
+ public static final int WIFI_STATE_OFF_SCANNING = 1;
+ /**
+ * Wifi on, but no saved infrastructure networks to connect to.
+ */
+ public static final int WIFI_STATE_ON_NO_NETWORKS = 2;
+ /**
+ * Wifi on, but not connected to any infrastructure networks.
+ */
+ public static final int WIFI_STATE_ON_DISCONNECTED = 3;
+ /**
+ * Wifi on and connected to a infrastructure network.
+ */
+ public static final int WIFI_STATE_ON_CONNECTED_STA = 4;
+ /**
+ * Wifi on and connected to a P2P device, but no infrastructure connection to a network.
+ */
+ public static final int WIFI_STATE_ON_CONNECTED_P2P = 5;
+ /**
+ * Wifi on and connected to both a P2P device and infrastructure connection to a network.
+ */
+ public static final int WIFI_STATE_ON_CONNECTED_STA_P2P = 6;
+ /**
+ * SoftAp/Hotspot turned on.
+ */
+ public static final int WIFI_STATE_SOFT_AP = 7;
+
+ /** @hide */
+ public static final int NUM_WIFI_STATES = WIFI_STATE_SOFT_AP + 1;
+
+ /** @hide */
+ @IntDef(flag = true, prefix = { "WIFI_STATE_" }, value = {
+ WIFI_STATE_OFF,
+ WIFI_STATE_OFF_SCANNING,
+ WIFI_STATE_ON_NO_NETWORKS,
+ WIFI_STATE_ON_DISCONNECTED,
+ WIFI_STATE_ON_CONNECTED_STA,
+ WIFI_STATE_ON_CONNECTED_P2P,
+ WIFI_STATE_ON_CONNECTED_STA_P2P,
+ WIFI_STATE_SOFT_AP
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface WifiState {}
+
+ /**
+ * Wifi supplicant daemon states.
+ *
+ * @see android.net.wifi.SupplicantState for detailed description of states.
+ * @see #noteWifiSupplicantStateChanged(int)
+ */
+ /** @see android.net.wifi.SupplicantState#INVALID */
+ public static final int WIFI_SUPPL_STATE_INVALID = 0;
+ /** @see android.net.wifi.SupplicantState#DISCONNECTED*/
+ public static final int WIFI_SUPPL_STATE_DISCONNECTED = 1;
+ /** @see android.net.wifi.SupplicantState#INTERFACE_DISABLED */
+ public static final int WIFI_SUPPL_STATE_INTERFACE_DISABLED = 2;
+ /** @see android.net.wifi.SupplicantState#INACTIVE*/
+ public static final int WIFI_SUPPL_STATE_INACTIVE = 3;
+ /** @see android.net.wifi.SupplicantState#SCANNING*/
+ public static final int WIFI_SUPPL_STATE_SCANNING = 4;
+ /** @see android.net.wifi.SupplicantState#AUTHENTICATING */
+ public static final int WIFI_SUPPL_STATE_AUTHENTICATING = 5;
+ /** @see android.net.wifi.SupplicantState#ASSOCIATING */
+ public static final int WIFI_SUPPL_STATE_ASSOCIATING = 6;
+ /** @see android.net.wifi.SupplicantState#ASSOCIATED */
+ public static final int WIFI_SUPPL_STATE_ASSOCIATED = 7;
+ /** @see android.net.wifi.SupplicantState#FOUR_WAY_HANDSHAKE */
+ public static final int WIFI_SUPPL_STATE_FOUR_WAY_HANDSHAKE = 8;
+ /** @see android.net.wifi.SupplicantState#GROUP_HANDSHAKE */
+ public static final int WIFI_SUPPL_STATE_GROUP_HANDSHAKE = 9;
+ /** @see android.net.wifi.SupplicantState#COMPLETED */
+ public static final int WIFI_SUPPL_STATE_COMPLETED = 10;
+ /** @see android.net.wifi.SupplicantState#DORMANT */
+ public static final int WIFI_SUPPL_STATE_DORMANT = 11;
+ /** @see android.net.wifi.SupplicantState#UNINITIALIZED */
+ public static final int WIFI_SUPPL_STATE_UNINITIALIZED = 12;
+
+ /** @hide */
+ public static final int NUM_WIFI_SUPPL_STATES = WIFI_SUPPL_STATE_UNINITIALIZED + 1;
+
+ /** @hide */
+ @IntDef(flag = true, prefix = { "WIFI_SUPPL_STATE_" }, value = {
+ WIFI_SUPPL_STATE_INVALID,
+ WIFI_SUPPL_STATE_DISCONNECTED,
+ WIFI_SUPPL_STATE_INTERFACE_DISABLED,
+ WIFI_SUPPL_STATE_INACTIVE,
+ WIFI_SUPPL_STATE_SCANNING,
+ WIFI_SUPPL_STATE_AUTHENTICATING,
+ WIFI_SUPPL_STATE_ASSOCIATING,
+ WIFI_SUPPL_STATE_ASSOCIATED,
+ WIFI_SUPPL_STATE_FOUR_WAY_HANDSHAKE,
+ WIFI_SUPPL_STATE_GROUP_HANDSHAKE,
+ WIFI_SUPPL_STATE_COMPLETED,
+ WIFI_SUPPL_STATE_DORMANT,
+ WIFI_SUPPL_STATE_UNINITIALIZED,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface WifiSupplState {}
+
private final IBatteryStats mBatteryStats;
/** @hide */
@@ -91,7 +205,7 @@ public class BatteryStatsManager {
* @param accessPoint SSID of the network if wifi is connected to STA, else null.
*/
@RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
- public void noteWifiState(@BatteryStats.WifiState int newWifiState,
+ public void noteWifiState(@WifiState int newWifiState,
@Nullable String accessPoint) {
try {
mBatteryStats.noteWifiState(newWifiState, accessPoint);
@@ -224,7 +338,7 @@ public class BatteryStatsManager {
* authentication failure.
*/
@RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
- public void noteWifiSupplicantStateChanged(@BatteryStats.WifiSupplState int newSupplState,
+ public void noteWifiSupplicantStateChanged(@WifiSupplState int newSupplState,
boolean failedAuth) {
try {
mBatteryStats.noteWifiSupplicantStateChanged(newSupplState, failedAuth);
diff --git a/core/java/android/os/connectivity/WifiBatteryStats.java b/core/java/android/os/connectivity/WifiBatteryStats.java
index e9b3837c8853..895d837a359e 100644
--- a/core/java/android/os/connectivity/WifiBatteryStats.java
+++ b/core/java/android/os/connectivity/WifiBatteryStats.java
@@ -19,6 +19,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.os.BatteryStats;
+import android.os.BatteryStatsManager;
import android.os.Parcel;
import android.os.Parcelable;
@@ -46,9 +47,9 @@ public final class WifiBatteryStats implements Parcelable {
private long mEnergyConsumedMaMillis = 0;
private long mNumAppScanRequest = 0;
private long[] mTimeInStateMillis =
- new long[BatteryStats.NUM_WIFI_STATES];
+ new long[BatteryStatsManager.NUM_WIFI_STATES];
private long[] mTimeInSupplicantStateMillis =
- new long[BatteryStats.NUM_WIFI_SUPPL_STATES];
+ new long[BatteryStatsManager.NUM_WIFI_SUPPL_STATES];
private long[] mTimeInRxSignalStrengthLevelMillis =
new long[BatteryStats.NUM_WIFI_SIGNAL_STRENGTH_BINS];
private long mMonitoredRailChargeConsumedMaMillis = 0;
@@ -369,7 +370,7 @@ public final class WifiBatteryStats implements Parcelable {
/** @hide */
public void setTimeInStateMillis(long[] t) {
mTimeInStateMillis = Arrays.copyOfRange(t, 0,
- Math.min(t.length, BatteryStats.NUM_WIFI_STATES));
+ Math.min(t.length, BatteryStatsManager.NUM_WIFI_STATES));
return;
}
@@ -383,7 +384,7 @@ public final class WifiBatteryStats implements Parcelable {
/** @hide */
public void setTimeInSupplicantStateMillis(long[] t) {
mTimeInSupplicantStateMillis = Arrays.copyOfRange(
- t, 0, Math.min(t.length, BatteryStats.NUM_WIFI_SUPPL_STATES));
+ t, 0, Math.min(t.length, BatteryStatsManager.NUM_WIFI_SUPPL_STATES));
return;
}
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 2d70986dddee..62603fee1137 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -80,6 +80,7 @@ import android.system.Os;
import android.system.OsConstants;
import android.text.TextUtils;
import android.util.DataUnit;
+import android.util.FeatureFlagUtils;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
@@ -156,7 +157,8 @@ public class StorageManager {
/** {@hide} */
public static final String PROP_FUSE = "persist.sys.fuse";
/** {@hide} */
- public static final String PROP_FUSE_SNAPSHOT = "sys.fuse_snapshot";
+ public static final String PROP_SETTINGS_FUSE = FeatureFlagUtils.PERSIST_PREFIX
+ + FeatureFlagUtils.SETTINGS_FUSE_FLAG;
/** {@hide} */
diff --git a/core/java/android/permission/PermissionControllerService.java b/core/java/android/permission/PermissionControllerService.java
index 8f765faa1a0b..f9146637c8cb 100644
--- a/core/java/android/permission/PermissionControllerService.java
+++ b/core/java/android/permission/PermissionControllerService.java
@@ -221,7 +221,7 @@ public abstract class PermissionControllerService extends Service {
* permission controller package.
*/
@BinderThread
- public void onUpdateUserSensitive() {
+ public void onUpdateUserSensitivePermissionFlags() {
throw new AbstractMethodError("Must be overridden in implementing class");
}
@@ -449,7 +449,7 @@ public abstract class PermissionControllerService extends Service {
public void updateUserSensitive(AndroidFuture callback) {
Preconditions.checkNotNull(callback, "callback cannot be null");
- onUpdateUserSensitive();
+ onUpdateUserSensitivePermissionFlags();
callback.complete(null);
}
};
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 8bf723fa54ed..eb1684f385d8 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -2916,6 +2916,8 @@ public final class ContactsContract {
*/
@Nullable
public static String getLocalAccountName(@NonNull Context context) {
+ // config_rawContactsLocalAccountName is defined in
+ // platform/frameworks/base/core/res/res/values/config.xml
return TextUtils.nullIfEmpty(context.getString(
com.android.internal.R.string.config_rawContactsLocalAccountName));
}
@@ -2933,6 +2935,8 @@ public final class ContactsContract {
*/
@Nullable
public static String getLocalAccountType(@NonNull Context context) {
+ // config_rawContactsLocalAccountType is defined in
+ // platform/frameworks/base/core/res/res/values/config.xml
return TextUtils.nullIfEmpty(context.getString(
com.android.internal.R.string.config_rawContactsLocalAccountType));
}
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 9dc680629260..ef22d70f715b 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -40,6 +40,7 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -578,11 +579,13 @@ public final class DeviceConfig {
* none or all of this update is picked up, but never only part of it.
*
* @param properties the complete set of properties to set for a specific namespace.
+ * @throws BadConfigException if the provided properties are banned by RescueParty.
+ * @return True if the values were set, false otherwise.
* @hide
*/
@SystemApi
@RequiresPermission(WRITE_DEVICE_CONFIG)
- public static boolean setProperties(@NonNull Properties properties) {
+ public static boolean setProperties(@NonNull Properties properties) throws BadConfigException {
ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
return Settings.Config.setStrings(contentResolver, properties.getNamespace(),
properties.mMap);
@@ -732,19 +735,19 @@ public final class DeviceConfig {
List<String> pathSegments = uri.getPathSegments();
// pathSegments(0) is "config"
final String namespace = pathSegments.get(1);
- Map<String, String> propertyMap = new ArrayMap<>();
+ Properties.Builder propBuilder = new Properties.Builder(namespace);
try {
Properties allProperties = getProperties(namespace);
for (int i = 2; i < pathSegments.size(); ++i) {
String key = pathSegments.get(i);
- propertyMap.put(key, allProperties.getString(key, null));
+ propBuilder.setString(key, allProperties.getString(key, null));
}
} catch (SecurityException e) {
// Silently failing to not crash binder or listener threads.
Log.e(TAG, "OnPropertyChangedListener update failed: permission violation.");
return;
}
- Properties properties = new Properties(namespace, propertyMap);
+ Properties properties = propBuilder.build();
synchronized (sLock) {
for (int i = 0; i < sListeners.size(); i++) {
@@ -799,6 +802,15 @@ public final class DeviceConfig {
}
/**
+ * Thrown by {@link #setProperties(Properties)} when a configuration is rejected. This
+ * happens if RescueParty has identified a bad configuration and reset the namespace.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static class BadConfigException extends Exception {}
+
+ /**
* A mapping of properties to values, as well as a single namespace which they all belong to.
*
* @hide
@@ -808,6 +820,7 @@ public final class DeviceConfig {
public static class Properties {
private final String mNamespace;
private final HashMap<String, String> mMap;
+ private Set<String> mKeyset;
/**
* Create a mapping of properties to values and the namespace they belong to.
@@ -838,7 +851,10 @@ public final class DeviceConfig {
*/
@NonNull
public Set<String> getKeyset() {
- return mMap.keySet();
+ if (mKeyset == null) {
+ mKeyset = Collections.unmodifiableSet(mMap.keySet());
+ }
+ return mKeyset;
}
/**
@@ -933,5 +949,93 @@ public final class DeviceConfig {
return defaultValue;
}
}
+
+ /**
+ * Builder class for the construction of {@link Properties} objects.
+ */
+ public static final class Builder {
+ @NonNull
+ private final String mNamespace;
+ @NonNull
+ private final Map<String, String> mKeyValues = new HashMap<>();
+
+ /**
+ * Create a new Builders for the specified namespace.
+ * @param namespace non null namespace.
+ */
+ public Builder(@NonNull String namespace) {
+ mNamespace = namespace;
+ }
+
+ /**
+ * Add a new property with the specified key and value.
+ * @param name non null name of the property.
+ * @param value nullable string value of the property.
+ * @return this Builder object
+ */
+ @NonNull
+ public Builder setString(@NonNull String name, @Nullable String value) {
+ mKeyValues.put(name, value);
+ return this;
+ }
+
+ /**
+ * Add a new property with the specified key and value.
+ * @param name non null name of the property.
+ * @param value nullable string value of the property.
+ * @return this Builder object
+ */
+ @NonNull
+ public Builder setBoolean(@NonNull String name, boolean value) {
+ mKeyValues.put(name, Boolean.toString(value));
+ return this;
+ }
+
+ /**
+ * Add a new property with the specified key and value.
+ * @param name non null name of the property.
+ * @param value int value of the property.
+ * @return this Builder object
+ */
+ @NonNull
+ public Builder setInt(@NonNull String name, int value) {
+ mKeyValues.put(name, Integer.toString(value));
+ return this;
+ }
+
+ /**
+ * Add a new property with the specified key and value.
+ * @param name non null name of the property.
+ * @param value long value of the property.
+ * @return this Builder object
+ */
+ @NonNull
+ public Builder setLong(@NonNull String name, long value) {
+ mKeyValues.put(name, Long.toString(value));
+ return this;
+ }
+
+ /**
+ * Add a new property with the specified key and value.
+ * @param name non null name of the property.
+ * @param value float value of the property.
+ * @return this Builder object
+ */
+ @NonNull
+ public Builder setFloat(@NonNull String name, float value) {
+ mKeyValues.put(name, Float.toString(value));
+ return this;
+ }
+
+ /**
+ * Create a new {@link Properties} object.
+ * @return non null Properties.
+ */
+ @NonNull
+ public Properties build() {
+ return new Properties(mNamespace, mKeyValues);
+ }
+ }
}
+
}
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 70c8e5d311bd..f6da01bfc966 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -25,6 +25,7 @@ import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.ChangeId;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.ContentValues;
@@ -4032,6 +4033,16 @@ public final class Telephony {
@Retention(RetentionPolicy.SOURCE)
public @interface Skip464XlatStatus {}
+ /**
+ * Compat framework change ID for the APN db read permission change.
+ *
+ * In API level 30 and beyond, accessing the APN database will require the
+ * {@link android.Manifest.permission#WRITE_APN_SETTINGS} permission. This change ID tracks
+ * apps that are affected because they don't hold this permission.
+ * @hide
+ */
+ @ChangeId
+ public static final long APN_READING_PERMISSION_CHANGE_ID = 124107808L;
}
/**
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
index 15ded8d1b7b1..e4ba87c14626 100644
--- a/core/java/android/security/keymaster/KeymasterDefs.java
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -94,6 +94,7 @@ 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_DEVICE_UNIQUE_ATTESTATION = KM_BOOL | 720;
public static final int KM_TAG_ASSOCIATED_DATA = KM_BYTES | 1000;
public static final int KM_TAG_NONCE = KM_BYTES | 1001;
diff --git a/core/java/android/service/controls/BooleanAction.java b/core/java/android/service/controls/BooleanAction.java
index 8508c635142f..877f82e96174 100644
--- a/core/java/android/service/controls/BooleanAction.java
+++ b/core/java/android/service/controls/BooleanAction.java
@@ -18,6 +18,7 @@ package android.service.controls;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.os.Bundle;
import android.os.Parcel;
/**
@@ -26,6 +27,8 @@ import android.os.Parcel;
*/
public final class BooleanAction extends ControlAction {
+ private static final String KEY_NEW_STATE = "key_new_state";
+
private final boolean mNewState;
/**
@@ -49,9 +52,9 @@ public final class BooleanAction extends ControlAction {
mNewState = newValue;
}
- BooleanAction(Parcel in) {
- super(in);
- mNewState = in.readByte() == 1;
+ BooleanAction(Bundle b) {
+ super(b);
+ mNewState = b.getBoolean(KEY_NEW_STATE);
}
/**
@@ -72,17 +75,17 @@ public final class BooleanAction extends ControlAction {
return ControlAction.TYPE_BOOLEAN;
}
-
@Override
- public void writeToParcel(Parcel dest, int flags) {
- super.writeToParcel(dest, flags);
- dest.writeByte(mNewState ? (byte) 1 : (byte) 0);
+ protected Bundle getDataBundle() {
+ Bundle b = super.getDataBundle();
+ b.putBoolean(KEY_NEW_STATE, mNewState);
+ return b;
}
public static final @NonNull Creator<BooleanAction> CREATOR = new Creator<BooleanAction>() {
@Override
public BooleanAction createFromParcel(Parcel source) {
- return new BooleanAction(source);
+ return new BooleanAction(source.readBundle());
}
@Override
diff --git a/core/java/android/service/controls/Control.java b/core/java/android/service/controls/Control.java
index a69408c43df3..2c17e89d02cc 100644
--- a/core/java/android/service/controls/Control.java
+++ b/core/java/android/service/controls/Control.java
@@ -18,6 +18,7 @@ package android.service.controls;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.PendingIntent;
import android.content.Intent;
import android.content.res.ColorStateList;
import android.graphics.drawable.Icon;
@@ -55,7 +56,7 @@ public class Control implements Parcelable {
private final @NonNull Icon mIcon;
private final @NonNull CharSequence mTitle;
private final @Nullable ColorStateList mTintColor;
- private final @NonNull Intent mAppIntent;
+ private final @NonNull PendingIntent mAppIntent;
private final @ControlTemplate.TemplateType int mPrimaryType;
/**
@@ -64,14 +65,15 @@ public class Control implements Parcelable {
* @param title the user facing name of this control (e.g. "Bedroom thermostat").
* @param tintColor the color to tint parts of the element UI. If {@code null} is passed, the
* system accent color will be used.
- * @param appIntent an intent linking to a page to interact with the corresponding device.
+ * @param appIntent a {@link PendingIntent} linking to a page to interact with the
+ * corresponding device.
* @param primaryType the primary template for this type.
*/
public Control(@NonNull String controlId,
@NonNull Icon icon,
@NonNull CharSequence title,
@Nullable ColorStateList tintColor,
- @NonNull Intent appIntent,
+ @NonNull PendingIntent appIntent,
int primaryType) {
Preconditions.checkNotNull(controlId);
Preconditions.checkNotNull(icon);
@@ -94,7 +96,7 @@ public class Control implements Parcelable {
} else {
mTintColor = null;
}
- mAppIntent = Intent.CREATOR.createFromParcel(in);
+ mAppIntent = PendingIntent.CREATOR.createFromParcel(in);
mPrimaryType = in.readInt();
}
@@ -119,7 +121,7 @@ public class Control implements Parcelable {
}
@NonNull
- public Intent getAppIntent() {
+ public PendingIntent getAppIntent() {
return mAppIntent;
}
@@ -175,17 +177,17 @@ public class Control implements Parcelable {
private Icon mIcon;
private CharSequence mTitle = "";
private ColorStateList mTintColor;
- private @Nullable Intent mAppIntent;
+ private @Nullable PendingIntent mAppIntent;
private @ControlTemplate.TemplateType int mPrimaryType = ControlTemplate.TYPE_NONE;
/**
* @param controlId the identifier for the {@link Control}.
* @param icon the icon for the {@link Control}.
- * @param appIntent the intent linking to the device Activity.
+ * @param appIntent the pending intent linking to the device Activity.
*/
public Builder(@NonNull String controlId,
@NonNull Icon icon,
- @NonNull Intent appIntent) {
+ @NonNull PendingIntent appIntent) {
Preconditions.checkNotNull(controlId);
Preconditions.checkNotNull(icon);
Preconditions.checkNotNull(appIntent);
@@ -256,7 +258,7 @@ public class Control implements Parcelable {
* @return {@code this}
*/
@NonNull
- public Builder setAppIntent(@NonNull Intent appIntent) {
+ public Builder setAppIntent(@NonNull PendingIntent appIntent) {
Preconditions.checkNotNull(appIntent);
mAppIntent = appIntent;
return this;
diff --git a/core/java/android/service/controls/ControlAction.java b/core/java/android/service/controls/ControlAction.java
index 8b759556b597..0a7c97c1bbc9 100644
--- a/core/java/android/service/controls/ControlAction.java
+++ b/core/java/android/service/controls/ControlAction.java
@@ -16,9 +16,11 @@
package android.service.controls;
+import android.annotation.CallSuper;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -36,25 +38,38 @@ import java.lang.annotation.RetentionPolicy;
*/
public abstract class ControlAction implements Parcelable {
+ private static final String KEY_TEMPLATE_ID = "key_template_id";
+ private static final String KEY_CHALLENGE_VALUE = "key_challenge_value";
+
+ public static final ControlAction UNKNOWN_ACTION = new ControlAction() {
+
+ @Override
+ public int getActionType() {
+ return TYPE_UNKNOWN;
+ }
+ };
+
/**
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef({
+ TYPE_UNKNOWN,
TYPE_BOOLEAN,
TYPE_FLOAT
})
public @interface ActionType {};
+ public static final @ActionType int TYPE_UNKNOWN = 0;
/**
* The identifier of {@link BooleanAction}.
*/
- public static final @ActionType int TYPE_BOOLEAN = 0;
+ public static final @ActionType int TYPE_BOOLEAN = 1;
/**
* The identifier of {@link FloatAction}.
*/
- public static final @ActionType int TYPE_FLOAT = 1;
+ public static final @ActionType int TYPE_FLOAT = 2;
/**
* @hide
@@ -120,13 +135,9 @@ public abstract class ControlAction implements Parcelable {
/**
* @hide
*/
- ControlAction(Parcel in) {
- mTemplateId = in.readString();
- if (in.readByte() == 1) {
- mChallengeValue = in.readString();
- } else {
- mChallengeValue = null;
- }
+ ControlAction(Bundle b) {
+ mTemplateId = b.getString(KEY_TEMPLATE_ID);
+ mChallengeValue = b.getString(KEY_CHALLENGE_VALUE);
}
/**
@@ -151,15 +162,24 @@ public abstract class ControlAction implements Parcelable {
}
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public final void writeToParcel(Parcel dest, int flags) {
dest.writeInt(getActionType());
- dest.writeString(mTemplateId);
- if (mChallengeValue != null) {
- dest.writeByte((byte) 1);
- dest.writeString(mChallengeValue);
- } else {
- dest.writeByte((byte) 0);
- }
+ dest.writeBundle(getDataBundle());
+ }
+
+ /**
+ * Obtain a {@link Bundle} describing this object populated with data.
+ *
+ * Implementations in subclasses should populate the {@link Bundle} returned by
+ * {@link ControlAction}.
+ * @return a {@link Bundle} containing the data that represents this object.
+ */
+ @CallSuper
+ protected Bundle getDataBundle() {
+ Bundle b = new Bundle();
+ b.putString(KEY_TEMPLATE_ID, mTemplateId);
+ b.putString(KEY_CHALLENGE_VALUE, mChallengeValue);
+ return b;
}
public static final @NonNull Creator<ControlAction> CREATOR = new Creator<ControlAction>() {
@@ -175,6 +195,7 @@ public abstract class ControlAction implements Parcelable {
}
};
+
private static ControlAction createActionFromType(@ActionType int type, Parcel source) {
switch(type) {
case TYPE_BOOLEAN:
@@ -182,7 +203,8 @@ public abstract class ControlAction implements Parcelable {
case TYPE_FLOAT:
return FloatAction.CREATOR.createFromParcel(source);
default:
- return null;
+ source.readBundle();
+ return UNKNOWN_ACTION;
}
}
diff --git a/core/java/android/service/controls/ControlButton.java b/core/java/android/service/controls/ControlButton.java
index fed31158be35..969c0a75f4ed 100644
--- a/core/java/android/service/controls/ControlButton.java
+++ b/core/java/android/service/controls/ControlButton.java
@@ -29,29 +29,29 @@ import com.android.internal.util.Preconditions;
*/
public class ControlButton implements Parcelable {
- private final boolean mActive;
+ private final boolean mChecked;
private final @NonNull Icon mIcon;
private final @NonNull CharSequence mContentDescription;
/**
- * @param active true if the button should be rendered as active.
+ * @param checked true if the button should be rendered as active.
* @param icon icon to display in the button.
* @param contentDescription content description for the button.
*/
- public ControlButton(boolean active, @NonNull Icon icon,
+ public ControlButton(boolean checked, @NonNull Icon icon,
@NonNull CharSequence contentDescription) {
Preconditions.checkNotNull(icon);
Preconditions.checkNotNull(contentDescription);
- mActive = active;
+ mChecked = checked;
mIcon = icon;
mContentDescription = contentDescription;
}
/**
- * Whether the button should be rendered in its active state.
+ * Whether the button should be rendered in a checked state.
*/
- public boolean isActive() {
- return mActive;
+ public boolean isChecked() {
+ return mChecked;
}
/**
@@ -78,13 +78,13 @@ public class ControlButton implements Parcelable {
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeByte(mActive ? (byte) 1 : (byte) 0);
+ dest.writeByte(mChecked ? (byte) 1 : (byte) 0);
mIcon.writeToParcel(dest, flags);
dest.writeCharSequence(mContentDescription);
}
ControlButton(Parcel in) {
- mActive = in.readByte() != 0;
+ mChecked = in.readByte() != 0;
mIcon = Icon.CREATOR.createFromParcel(in);
mContentDescription = in.readCharSequence();
}
diff --git a/core/java/android/service/controls/ControlState.java b/core/java/android/service/controls/ControlState.java
index 804aef798eb5..f2410a8ea7c1 100644
--- a/core/java/android/service/controls/ControlState.java
+++ b/core/java/android/service/controls/ControlState.java
@@ -19,6 +19,7 @@ package android.service.controls;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.PendingIntent;
import android.content.res.ColorStateList;
import android.graphics.drawable.Icon;
import android.os.Parcel;
@@ -33,11 +34,11 @@ import java.lang.annotation.RetentionPolicy;
* Current state for a {@link Control}.
*
* Collects information to render the current state of a {@link Control} as well as possible action
- * that can be performed on it. Some of the information may temporarily override the defaults
- * provided by the corresponding {@link Control}, while this state is being displayed.
- *
- * Additionally, this can be used to modify information related to the corresponding
- * {@link Control}.
+ * that can be performed on it.
+ * <p>
+ * Additionally, this object is used to modify elements from the {@link Control} such as icons,
+ * colors, names and intents. This information will last until it is again modified by a
+ * {@link ControlState}.
* @hide
*/
public final class ControlState implements Parcelable {
@@ -74,58 +75,81 @@ public final class ControlState implements Parcelable {
*/
public static final int STATUS_DISABLED = 3;
- private final @NonNull Control mControl;
+ private final @NonNull String mControlId;
private final @Status int mStatus;
private final @NonNull ControlTemplate mControlTemplate;
private final @NonNull CharSequence mStatusText;
- private final @Nullable Icon mOverrideIcon;
- private final @Nullable ColorStateList mOverrideTint;
+ private final @Nullable CharSequence mTitle;
+ private final @Nullable PendingIntent mAppIntent;
+ private final @Nullable Icon mIcon;
+ private final @Nullable ColorStateList mTint;
/**
- * @param control the {@link Control} this state should be applied to. Can be used to
- * update information about the {@link Control}
+ * @param controlId the identifier of the {@link Control} this object refers to.
* @param status the current status of the {@link Control}.
- * @param controlTemplate the template to be used to render the {@link Control}.
- * @param statusText the text describing the current status.
- * @param overrideIcon the icon to temporarily override the one provided in
- * {@link Control#getIcon()}. Pass {@code null} to use the icon in
- * {@link Control#getIcon()}.
- * @param overrideTint the colors to temporarily override those provided in
- * {@link Control#getTint()}. Pass {@code null} to use the colors in
- * {@link Control#getTint()}.
+ * @param controlTemplate the template to be used to render the {@link Control}. This can be
+ * of a different
+ * {@link android.service.controls.ControlTemplate.TemplateType} than the
+ * one defined in {@link Control#getPrimaryType}
+ * @param statusText the user facing text describing the current status.
+ * @param title the title to replace the one set in the {@link Control} or set in the
+ * last {@link ControlState}. Pass {@code null} to use the last value set for this
+ * {@link Control}
+ * @param appIntent the {@link PendingIntent} to replace the one set in the {@link Control} or
+ * set in the last {@link ControlState}. Pass {@code null} to use the last
+ * value set for this {@link Control}.
+ * @param icon the icon to replace the one set in the {@link Control} or set in the last
+ * {@link ControlState}. Pass {@code null} to use the last value set for this
+ * {@link Control}.
+ * @param tint the colors to replace those set in the {@link Control} or set in the last
+ * {@link ControlState}. Pass {@code null} to use the last value set for this
+ * {@link Control}.
*/
- public ControlState(@NonNull Control control,
+ public ControlState(@NonNull String controlId,
int status,
@NonNull ControlTemplate controlTemplate,
@NonNull CharSequence statusText,
- @Nullable Icon overrideIcon,
- @Nullable ColorStateList overrideTint) {
- Preconditions.checkNotNull(control);
+ @Nullable CharSequence title,
+ @Nullable PendingIntent appIntent,
+ @Nullable Icon icon,
+ @Nullable ColorStateList tint) {
+ Preconditions.checkNotNull(controlId);
Preconditions.checkNotNull(controlTemplate);
Preconditions.checkNotNull(statusText);
-
- mControl = control;
+ mControlId = controlId;
mStatus = status;
mControlTemplate = controlTemplate;
- mOverrideIcon = overrideIcon;
mStatusText = statusText;
- mOverrideTint = overrideTint;
+ mTitle = title;
+ mAppIntent = appIntent;
+ mIcon = icon;
+ mTint = tint;
}
ControlState(Parcel in) {
- mControl = Control.CREATOR.createFromParcel(in);
+ mControlId = in.readString();
mStatus = in.readInt();
mControlTemplate = ControlTemplate.CREATOR.createFromParcel(in);
mStatusText = in.readCharSequence();
if (in.readByte() == 1) {
- mOverrideIcon = Icon.CREATOR.createFromParcel(in);
+ mTitle = in.readCharSequence();
+ } else {
+ mTitle = null;
+ }
+ if (in.readByte() == 1) {
+ mAppIntent = PendingIntent.CREATOR.createFromParcel(in);
+ } else {
+ mAppIntent = null;
+ }
+ if (in.readByte() == 1) {
+ mIcon = Icon.CREATOR.createFromParcel(in);
} else {
- mOverrideIcon = null;
+ mIcon = null;
}
if (in.readByte() == 1) {
- mOverrideTint = ColorStateList.CREATOR.createFromParcel(in);
+ mTint = ColorStateList.CREATOR.createFromParcel(in);
} else {
- mOverrideTint = null;
+ mTint = null;
}
}
@@ -134,6 +158,21 @@ public final class ControlState implements Parcelable {
return 0;
}
+ @NonNull
+ public String getControlId() {
+ return mControlId;
+ }
+
+ @Nullable
+ public CharSequence getTitle() {
+ return mTitle;
+ }
+
+ @Nullable
+ public PendingIntent getAppIntent() {
+ return mAppIntent;
+ }
+
@Status
public int getStatus() {
return mStatus;
@@ -145,8 +184,8 @@ public final class ControlState implements Parcelable {
}
@Nullable
- public Icon getOverrideIcon() {
- return mOverrideIcon;
+ public Icon getIcon() {
+ return mIcon;
}
@NonNull
@@ -155,35 +194,35 @@ public final class ControlState implements Parcelable {
}
@Nullable
- public ColorStateList getOverrideTint() {
- return mOverrideTint;
- }
-
- @NonNull
- public Control getControl() {
- return mControl;
- }
-
- @NonNull
- public String getControlId() {
- return mControl.getControlId();
+ public ColorStateList getTint() {
+ return mTint;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
- mControl.writeToParcel(dest, flags);
+ dest.writeString(mControlId);
dest.writeInt(mStatus);
mControlTemplate.writeToParcel(dest, flags);
dest.writeCharSequence(mStatusText);
- if (mOverrideIcon != null) {
+ if (mTitle != null) {
dest.writeByte((byte) 1);
- mOverrideIcon.writeToParcel(dest, flags);
+ dest.writeCharSequence(mTitle);
} else {
dest.writeByte((byte) 0);
}
- if (mOverrideTint != null) {
+ if (mAppIntent != null) {
+ dest.writeByte((byte) 1);
+ mAppIntent.writeToParcel(dest, flags);
+ }
+ if (mIcon != null) {
dest.writeByte((byte) 1);
- mOverrideTint.writeToParcel(dest, flags);
+ mIcon.writeToParcel(dest, flags);
+ } else {
+ dest.writeByte((byte) 0);
+ }
+ if (mTint != null) {
+ dest.writeByte((byte) 1);
+ mTint.writeToParcel(dest, flags);
} else {
dest.writeByte((byte) 0);
}
@@ -213,19 +252,22 @@ public final class ControlState implements Parcelable {
* </ul>
*/
public static class Builder {
- private @NonNull Control mControl;
+ private @NonNull String mControlId;
private @Status int mStatus = STATUS_OK;
private @NonNull ControlTemplate mControlTemplate = ControlTemplate.NO_TEMPLATE;
private @NonNull CharSequence mStatusText = "";
- private @Nullable Icon mOverrideIcon;
- private @Nullable ColorStateList mOverrideTint;
+ private @Nullable CharSequence mTitle;
+ private @Nullable PendingIntent mAppIntent;
+ private @Nullable Icon mIcon;
+ private @Nullable ColorStateList mTint;
/**
- * @param control the {@link Control} that the resulting {@link ControlState} refers to.
+ * @param controlId the identifier of the {@link Control} that the resulting
+ * {@link ControlState} refers to.
*/
- public Builder(@NonNull Control control) {
- Preconditions.checkNotNull(control);
- mControl = control;
+ public Builder(@NonNull String controlId) {
+ Preconditions.checkNotNull(controlId);
+ mControlId = controlId;
}
/**
@@ -234,21 +276,24 @@ public final class ControlState implements Parcelable {
*/
public Builder(@NonNull ControlState controlState) {
Preconditions.checkNotNull(controlState);
- mControl = controlState.mControl;
+ mControlId = controlState.mControlId;
+ mStatus = controlState.mStatus;
mControlTemplate = controlState.mControlTemplate;
- mOverrideIcon = controlState.mOverrideIcon;
mStatusText = controlState.mStatusText;
- mOverrideTint = controlState.mOverrideTint;
+ mTitle = controlState.mTitle;
+ mAppIntent = controlState.mAppIntent;
+ mIcon = controlState.mIcon;
+ mTint = controlState.mTint;
}
/**
- * @param control the updated {@link Control} information.
+ * @param controlId the identifier of the {@link Control} for the resulting object.
* @return {@code this}
*/
@NonNull
- public Builder setControl(@NonNull Control control) {
- mControl = control;
+ public Builder setControlId(@NonNull String controlId) {
+ mControlId = controlId;
return this;
}
@@ -285,24 +330,50 @@ public final class ControlState implements Parcelable {
}
/**
- * @param overrideIcon the icon to override the one defined in the corresponding
- * {@code Control}. Pass {@code null} to remove the override.
+ * @param title the title to replace the one defined in the corresponding {@link Control} or
+ * set by the last {@link ControlState}. Pass {@code null} to keep the last
+ * value.
+ * @return {@code this}
+ */
+ @NonNull
+ public Builder setTitle(@Nullable CharSequence title) {
+ mTitle = title;
+ return this;
+ }
+
+ /**
+ * @param appIntent the Pending Intent to replace the one defined in the corresponding
+ * {@link Control} or set by the last {@link ControlState}. Pass
+ * {@code null} to keep the last value.
+ * @return {@code this}
+ */
+ @NonNull
+ public Builder setAppIntent(@Nullable PendingIntent appIntent) {
+ mAppIntent = appIntent;
+ return this;
+ }
+
+ /**
+ * @param icon the title to replace the one defined in the corresponding {@link Control} or
+ * set by the last {@link ControlState}. Pass {@code null} to keep the last
+ * value.
* @return {@code this}
*/
@NonNull
- public Builder setOverrideIcon(@Nullable Icon overrideIcon) {
- mOverrideIcon = overrideIcon;
+ public Builder setIcon(@Nullable Icon icon) {
+ mIcon = icon;
return this;
}
/**
- * @param overrideTint the colors to override the ones defined in the corresponding
- * {@code Control}. Pass {@code null} to remove the override.
+ * @param tint the title to replace the one defined in the corresponding {@link Control} or
+ * set by the last {@link ControlState}. Pass {@code null} to keep the last
+ * value.
* @return {@code this}
*/
@NonNull
- public Builder setOverrideTint(@Nullable ColorStateList overrideTint) {
- mOverrideTint = overrideTint;
+ public Builder setTint(@Nullable ColorStateList tint) {
+ mTint = tint;
return this;
}
@@ -310,8 +381,8 @@ public final class ControlState implements Parcelable {
* @return a new {@link ControlState}
*/
public ControlState build() {
- return new ControlState(mControl, mStatus, mControlTemplate, mStatusText,
- mOverrideIcon, mOverrideTint);
+ return new ControlState(mControlId, mStatus, mControlTemplate, mStatusText,
+ mTitle, mAppIntent, mIcon, mTint);
}
}
}
diff --git a/core/java/android/service/controls/ControlTemplate.java b/core/java/android/service/controls/ControlTemplate.java
index e559862e86d6..8bcabd6972a5 100644
--- a/core/java/android/service/controls/ControlTemplate.java
+++ b/core/java/android/service/controls/ControlTemplate.java
@@ -16,8 +16,10 @@
package android.service.controls;
+import android.annotation.CallSuper;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -40,6 +42,8 @@ import java.lang.annotation.RetentionPolicy;
*/
public abstract class ControlTemplate implements Parcelable {
+ private static final String KEY_TEMPLATE_ID = "key_template_id";
+
/**
* Singleton representing a {@link Control} with no input.
*/
@@ -114,17 +118,28 @@ public abstract class ControlTemplate implements Parcelable {
}
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public final void writeToParcel(Parcel dest, int flags) {
dest.writeInt(getTemplateType());
- dest.writeString(mTemplateId);
+ dest.writeBundle(getDataBundle());
+ }
+
+ /**
+ * Obtain a {@link Bundle} describing this object populated with data.
+ * @return a {@link Bundle} containing the data that represents this object.
+ */
+ @CallSuper
+ protected Bundle getDataBundle() {
+ Bundle b = new Bundle();
+ b.putString(KEY_TEMPLATE_ID, mTemplateId);
+ return b;
}
private ControlTemplate() {
mTemplateId = "";
}
- ControlTemplate(Parcel in) {
- mTemplateId = in.readString();
+ ControlTemplate(@NonNull Bundle b) {
+ mTemplateId = b.getString(KEY_TEMPLATE_ID);
}
/**
@@ -148,6 +163,7 @@ public abstract class ControlTemplate implements Parcelable {
}
};
+
private static ControlTemplate createTemplateFromType(@TemplateType int type, Parcel source) {
switch(type) {
case TYPE_TOGGLE:
@@ -159,9 +175,9 @@ public abstract class ControlTemplate implements Parcelable {
case TYPE_DISCRETE_TOGGLE:
return DiscreteToggleTemplate.CREATOR.createFromParcel(source);
case TYPE_NONE:
- return NO_TEMPLATE;
default:
- return null;
+ source.readBundle();
+ return NO_TEMPLATE;
}
}
}
diff --git a/core/java/android/service/controls/DiscreteToggleTemplate.java b/core/java/android/service/controls/DiscreteToggleTemplate.java
index 5167af41c2f0..571825299c77 100644
--- a/core/java/android/service/controls/DiscreteToggleTemplate.java
+++ b/core/java/android/service/controls/DiscreteToggleTemplate.java
@@ -17,6 +17,7 @@
package android.service.controls;
import android.annotation.NonNull;
+import android.os.Bundle;
import android.os.Parcel;
import com.android.internal.util.Preconditions;
@@ -34,6 +35,9 @@ import com.android.internal.util.Preconditions;
*/
public class DiscreteToggleTemplate extends ControlTemplate {
+ private static final String KEY_NEGATIVE_BUTTON = "key_negative_button";
+ private static final String KEY_POSITIVE_BUTTON = "key_positive_button";
+
private final @NonNull ControlButton mNegativeButton;
private final @NonNull ControlButton mPositiveButton;
@@ -52,10 +56,10 @@ public class DiscreteToggleTemplate extends ControlTemplate {
mPositiveButton = positiveButton;
}
- DiscreteToggleTemplate(Parcel in) {
- super(in);
- this.mNegativeButton = ControlButton.CREATOR.createFromParcel(in);
- this.mPositiveButton = ControlButton.CREATOR.createFromParcel(in);
+ DiscreteToggleTemplate(Bundle b) {
+ super(b);
+ mNegativeButton = b.getParcelable(KEY_NEGATIVE_BUTTON);
+ mPositiveButton = b.getParcelable(KEY_POSITIVE_BUTTON);
}
/**
@@ -89,17 +93,18 @@ public class DiscreteToggleTemplate extends ControlTemplate {
}
@Override
- public void writeToParcel(Parcel dest, int flags) {
- super.writeToParcel(dest, flags);
- mNegativeButton.writeToParcel(dest, flags);
- mPositiveButton.writeToParcel(dest, flags);
+ protected Bundle getDataBundle() {
+ Bundle b = super.getDataBundle();
+ b.putObject(KEY_NEGATIVE_BUTTON, mNegativeButton);
+ b.putObject(KEY_POSITIVE_BUTTON, mPositiveButton);
+ return b;
}
public static final Creator<DiscreteToggleTemplate> CREATOR =
new Creator<DiscreteToggleTemplate>() {
@Override
public DiscreteToggleTemplate createFromParcel(Parcel source) {
- return new DiscreteToggleTemplate(source);
+ return new DiscreteToggleTemplate(source.readBundle());
}
@Override
diff --git a/core/java/android/service/controls/FloatAction.java b/core/java/android/service/controls/FloatAction.java
index fe6db10a98cd..229435f647a2 100644
--- a/core/java/android/service/controls/FloatAction.java
+++ b/core/java/android/service/controls/FloatAction.java
@@ -18,6 +18,7 @@ package android.service.controls;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.os.Bundle;
import android.os.Parcel;
/**
@@ -26,6 +27,8 @@ import android.os.Parcel;
*/
public final class FloatAction extends ControlAction {
+ private static final String KEY_NEW_VALUE = "key_new_value";
+
private final float mNewValue;
/**
@@ -50,9 +53,9 @@ public final class FloatAction extends ControlAction {
mNewValue = newValue;
}
- public FloatAction(Parcel in) {
- super(in);
- mNewValue = in.readFloat();
+ public FloatAction(Bundle b) {
+ super(b);
+ mNewValue = b.getFloat(KEY_NEW_VALUE);
}
/**
@@ -71,15 +74,16 @@ public final class FloatAction extends ControlAction {
}
@Override
- public void writeToParcel(Parcel dest, int flags) {
- super.writeToParcel(dest, flags);
- dest.writeFloat(mNewValue);
+ protected Bundle getDataBundle() {
+ Bundle b = super.getDataBundle();
+ b.putFloat(KEY_NEW_VALUE, mNewValue);
+ return b;
}
public static final @NonNull Creator<FloatAction> CREATOR = new Creator<FloatAction>() {
@Override
public FloatAction createFromParcel(Parcel source) {
- return new FloatAction(source);
+ return new FloatAction(source.readBundle());
}
@Override
diff --git a/core/java/android/service/controls/RangeTemplate.java b/core/java/android/service/controls/RangeTemplate.java
index 70bf2dd4aad4..f0bce30081b8 100644
--- a/core/java/android/service/controls/RangeTemplate.java
+++ b/core/java/android/service/controls/RangeTemplate.java
@@ -18,10 +18,9 @@ package android.service.controls;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.os.Bundle;
import android.os.Parcel;
-import com.android.internal.util.Preconditions;
-
import java.security.InvalidParameterException;
/**
@@ -32,6 +31,12 @@ import java.security.InvalidParameterException;
*/
public final class RangeTemplate extends ControlTemplate {
+ private static final String KEY_MIN_VALUE = "key_min_value";
+ private static final String KEY_MAX_VALUE = "key_max_value";
+ private static final String KEY_CURRENT_VALUE = "key_current_value";
+ private static final String KEY_STEP_VALUE = "key_step_value";
+ private static final String KEY_FORMAT_STRING = "key_format_string";
+
private final float mMinValue;
private final float mMaxValue;
private final float mCurrentValue;
@@ -67,7 +72,6 @@ public final class RangeTemplate extends ControlTemplate {
float stepValue,
@Nullable CharSequence formatString) {
super(templateId);
- Preconditions.checkNotNull(formatString);
mMinValue = minValue;
mMaxValue = maxValue;
mCurrentValue = currentValue;
@@ -87,13 +91,13 @@ public final class RangeTemplate extends ControlTemplate {
* @see RangeTemplate#RangeTemplate(String, float, float, float, float, CharSequence)
* @hide
*/
- RangeTemplate(Parcel in) {
- super(in);
- mMinValue = in.readFloat();
- mMaxValue = in.readFloat();
- mCurrentValue = in.readFloat();
- mStepValue = in.readFloat();
- mFormatString = in.readCharSequence();
+ RangeTemplate(Bundle b) {
+ super(b);
+ mMinValue = b.getFloat(KEY_MIN_VALUE);
+ mMaxValue = b.getFloat(KEY_MAX_VALUE);
+ mCurrentValue = b.getFloat(KEY_CURRENT_VALUE);
+ mStepValue = b.getFloat(KEY_STEP_VALUE);
+ mFormatString = b.getCharSequence(KEY_FORMAT_STRING, "%.1f");
validate();
}
@@ -144,13 +148,14 @@ public final class RangeTemplate extends ControlTemplate {
}
@Override
- public void writeToParcel(Parcel dest, int flags) {
- super.writeToParcel(dest, flags);
- dest.writeFloat(mMinValue);
- dest.writeFloat(mMaxValue);
- dest.writeFloat(mCurrentValue);
- dest.writeFloat(mStepValue);
- dest.writeCharSequence(mFormatString);
+ protected Bundle getDataBundle() {
+ Bundle b = super.getDataBundle();
+ b.putFloat(KEY_MIN_VALUE, mMinValue);
+ b.putFloat(KEY_MAX_VALUE, mMaxValue);
+ b.putFloat(KEY_CURRENT_VALUE, mCurrentValue);
+ b.putFloat(KEY_STEP_VALUE, mStepValue);
+ b.putCharSequence(KEY_FORMAT_STRING, mFormatString);
+ return b;
}
/**
@@ -179,7 +184,7 @@ public final class RangeTemplate extends ControlTemplate {
public static final Creator<RangeTemplate> CREATOR = new Creator<RangeTemplate>() {
@Override
public RangeTemplate createFromParcel(Parcel source) {
- return new RangeTemplate(source);
+ return new RangeTemplate(source.readBundle());
}
@Override
diff --git a/core/java/android/service/controls/ThumbnailTemplate.java b/core/java/android/service/controls/ThumbnailTemplate.java
index 796d2de89576..6e729c011196 100644
--- a/core/java/android/service/controls/ThumbnailTemplate.java
+++ b/core/java/android/service/controls/ThumbnailTemplate.java
@@ -18,6 +18,7 @@ package android.service.controls;
import android.annotation.NonNull;
import android.graphics.drawable.Icon;
+import android.os.Bundle;
import android.os.Parcel;
import com.android.internal.util.Preconditions;
@@ -28,6 +29,9 @@ import com.android.internal.util.Preconditions;
*/
public final class ThumbnailTemplate extends ControlTemplate {
+ private static final String KEY_ICON = "key_icon";
+ private static final String KEY_CONTENT_DESCRIPTION = "key_content_description";
+
private final @NonNull Icon mThumbnail;
private final @NonNull CharSequence mContentDescription;
@@ -45,10 +49,10 @@ public final class ThumbnailTemplate extends ControlTemplate {
mContentDescription = contentDescription;
}
- ThumbnailTemplate(Parcel in) {
- super(in);
- mThumbnail = Icon.CREATOR.createFromParcel(in);
- mContentDescription = in.readCharSequence();
+ ThumbnailTemplate(Bundle b) {
+ super(b);
+ mThumbnail = b.getParcelable(KEY_ICON);
+ mContentDescription = b.getCharSequence(KEY_CONTENT_DESCRIPTION, "");
}
/**
@@ -74,17 +78,19 @@ public final class ThumbnailTemplate extends ControlTemplate {
public int getTemplateType() {
return TYPE_THUMBNAIL;
}
+
@Override
- public void writeToParcel(Parcel dest, int flags) {
- super.writeToParcel(dest, flags);
- mThumbnail.writeToParcel(dest, flags);
- dest.writeCharSequence(mContentDescription);
+ protected Bundle getDataBundle() {
+ Bundle b = super.getDataBundle();
+ b.putObject(KEY_ICON, mThumbnail);
+ b.putObject(KEY_CONTENT_DESCRIPTION, mContentDescription);
+ return b;
}
public static final Creator<ThumbnailTemplate> CREATOR = new Creator<ThumbnailTemplate>() {
@Override
public ThumbnailTemplate createFromParcel(Parcel source) {
- return new ThumbnailTemplate(source);
+ return new ThumbnailTemplate(source.readBundle());
}
@Override
diff --git a/core/java/android/service/controls/ToggleTemplate.java b/core/java/android/service/controls/ToggleTemplate.java
index 3766bd168477..4c4fd5e33cde 100644
--- a/core/java/android/service/controls/ToggleTemplate.java
+++ b/core/java/android/service/controls/ToggleTemplate.java
@@ -17,6 +17,7 @@
package android.service.controls;
import android.annotation.NonNull;
+import android.os.Bundle;
import android.os.Parcel;
import com.android.internal.util.Preconditions;
@@ -24,7 +25,7 @@ import com.android.internal.util.Preconditions;
/**
* A template for a {@link Control} with a single button that can be toggled between two states.
*
- * The states for the toggle correspond to the states in {@link ControlButton#isActive()}.
+ * The states for the toggle correspond to the states in {@link ControlButton#isChecked()}.
* An action on this template will originate a {@link BooleanAction} to change that state.
*
* @see BooleanAction
@@ -32,6 +33,7 @@ import com.android.internal.util.Preconditions;
*/
public final class ToggleTemplate extends ControlTemplate {
+ private static final String KEY_BUTTON = "key_button";
private final @NonNull ControlButton mButton;
/**
@@ -44,9 +46,9 @@ public final class ToggleTemplate extends ControlTemplate {
mButton = button;
}
- ToggleTemplate(Parcel in) {
- super(in);
- mButton = ControlButton.CREATOR.createFromParcel(in);
+ ToggleTemplate(Bundle b) {
+ super(b);
+ mButton = b.getParcelable(KEY_BUTTON);
}
/**
@@ -66,15 +68,16 @@ public final class ToggleTemplate extends ControlTemplate {
}
@Override
- public void writeToParcel(Parcel dest, int flags) {
- super.writeToParcel(dest, flags);
- mButton.writeToParcel(dest, flags);
+ protected Bundle getDataBundle() {
+ Bundle b = super.getDataBundle();
+ b.putObject(KEY_BUTTON, mButton);
+ return b;
}
public static final Creator<ToggleTemplate> CREATOR = new Creator<ToggleTemplate>() {
@Override
public ToggleTemplate createFromParcel(Parcel source) {
- return new ToggleTemplate(source);
+ return new ToggleTemplate(source.readBundle());
}
@Override
diff --git a/core/java/android/text/format/DateUtils.java b/core/java/android/text/format/DateUtils.java
index b00a9385eec8..0c279230fab0 100644
--- a/core/java/android/text/format/DateUtils.java
+++ b/core/java/android/text/format/DateUtils.java
@@ -59,8 +59,12 @@ public class DateUtils
public static final long DAY_IN_MILLIS = HOUR_IN_MILLIS * 24;
public static final long WEEK_IN_MILLIS = DAY_IN_MILLIS * 7;
/**
- * This constant is actually the length of 364 days, not of a year!
+ * @deprecated Not all years have the same number of days, and this constant is actually the
+ * length of 364 days. Please use other date/time constructs such as
+ * {@link java.util.concurrent.TimeUnit}, {@link java.util.Calendar} or
+ * {@link java.time.Duration} instead.
*/
+ @Deprecated
public static final long YEAR_IN_MILLIS = WEEK_IN_MILLIS * 52;
// The following FORMAT_* symbols are used for specifying the format of
diff --git a/core/java/android/util/CloseGuard.java b/core/java/android/util/CloseGuard.java
new file mode 100644
index 000000000000..c39a6c9aac93
--- /dev/null
+++ b/core/java/android/util/CloseGuard.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2019 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 android.util;
+
+import android.annotation.NonNull;
+
+/**
+ * CloseGuard is a mechanism for flagging implicit finalizer cleanup of
+ * resources that should have been cleaned up by explicit close
+ * methods (aka "explicit termination methods" in Effective Java).
+ * <p>
+ * A simple example: <pre> {@code
+ * class Foo {
+ *
+ * private final CloseGuard guard = CloseGuard.get();
+ *
+ * ...
+ *
+ * public Foo() {
+ * ...;
+ * guard.open("cleanup");
+ * }
+ *
+ * public void cleanup() {
+ * guard.close();
+ * ...;
+ * }
+ *
+ * protected void finalize() throws Throwable {
+ * try {
+ * // Note that guard could be null if the constructor threw.
+ * if (guard != null) {
+ * guard.warnIfOpen();
+ * }
+ * cleanup();
+ * } finally {
+ * super.finalize();
+ * }
+ * }
+ * }
+ * }</pre>
+ *
+ * In usage where the resource to be explicitly cleaned up is
+ * allocated after object construction, CloseGuard protection can
+ * be deferred. For example: <pre> {@code
+ * class Bar {
+ *
+ * private final CloseGuard guard = CloseGuard.get();
+ *
+ * ...
+ *
+ * public Bar() {
+ * ...;
+ * }
+ *
+ * public void connect() {
+ * ...;
+ * guard.open("cleanup");
+ * }
+ *
+ * public void cleanup() {
+ * guard.close();
+ * ...;
+ * Reference.reachabilityFence(this);
+ * // For full correctness in the absence of a close() call, other methods may also need
+ * // reachabilityFence() calls.
+ * }
+ *
+ * protected void finalize() throws Throwable {
+ * try {
+ * // Note that guard could be null if the constructor threw.
+ * if (guard != null) {
+ * guard.warnIfOpen();
+ * }
+ * cleanup();
+ * } finally {
+ * super.finalize();
+ * }
+ * }
+ * }
+ * }</pre>
+ *
+ * When used in a constructor, calls to {@code open} should occur at
+ * the end of the constructor since an exception that would cause
+ * abrupt termination of the constructor will mean that the user will
+ * not have a reference to the object to cleanup explicitly. When used
+ * in a method, the call to {@code open} should occur just after
+ * resource acquisition.
+ */
+public final class CloseGuard {
+ private final dalvik.system.CloseGuard mImpl;
+
+ /**
+ * Constructs a new CloseGuard instance.
+ * {@link #open(String)} can be used to set up the instance to warn on failure to close.
+ */
+ public CloseGuard() {
+ mImpl = dalvik.system.CloseGuard.get();
+ }
+
+ /**
+ * Initializes the instance with a warning that the caller should have explicitly called the
+ * {@code closeMethodName} method instead of relying on finalization.
+ *
+ * @param closeMethodName non-null name of explicit termination method. Printed by warnIfOpen.
+ * @throws NullPointerException if closeMethodName is null.
+ */
+ public void open(@NonNull String closeMethodName) {
+ mImpl.open(closeMethodName);
+ }
+
+ /** Marks this CloseGuard instance as closed to avoid warnings on finalization. */
+ public void close() {
+ mImpl.close();
+ }
+
+ /**
+ * Logs a warning if the caller did not properly cleanup by calling an explicit close method
+ * before finalization.
+ */
+ public void warnIfOpen() {
+ mImpl.warnIfOpen();
+ }
+}
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 236e5ae6f952..1b2db36c1335 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -59,6 +59,7 @@ public class FeatureFlagUtils {
DEFAULT_FLAGS.put(SETTINGS_WIFITRACKER2, "false");
DEFAULT_FLAGS.put("settings_work_profile", "true");
DEFAULT_FLAGS.put("settings_controller_loading_enhancement", "false");
+ DEFAULT_FLAGS.put("settings_conditionals", "false");
}
/**
diff --git a/core/java/android/util/StatsLog.java b/core/java/android/util/StatsLog.java
index 9ac4cf267b47..952d7cbcd119 100644
--- a/core/java/android/util/StatsLog.java
+++ b/core/java/android/util/StatsLog.java
@@ -24,7 +24,7 @@ import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.content.Context;
-import android.os.IStatsManager;
+import android.os.IStatsd;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -36,7 +36,7 @@ public final class StatsLog extends StatsLogInternal {
private static final String TAG = "StatsLog";
private static final boolean DEBUG = false;
- private static IStatsManager sService;
+ private static IStatsd sService;
private static Object sLogLock = new Object();
@@ -52,7 +52,7 @@ public final class StatsLog extends StatsLogInternal {
public static boolean logStart(int label) {
synchronized (sLogLock) {
try {
- IStatsManager service = getIStatsManagerLocked();
+ IStatsd service = getIStatsdLocked();
if (service == null) {
if (DEBUG) {
Slog.d(TAG, "Failed to find statsd when logging start");
@@ -81,7 +81,7 @@ public final class StatsLog extends StatsLogInternal {
public static boolean logStop(int label) {
synchronized (sLogLock) {
try {
- IStatsManager service = getIStatsManagerLocked();
+ IStatsd service = getIStatsdLocked();
if (service == null) {
if (DEBUG) {
Slog.d(TAG, "Failed to find statsd when logging stop");
@@ -109,7 +109,7 @@ public final class StatsLog extends StatsLogInternal {
public static boolean logEvent(int label) {
synchronized (sLogLock) {
try {
- IStatsManager service = getIStatsManagerLocked();
+ IStatsd service = getIStatsdLocked();
if (service == null) {
if (DEBUG) {
Slog.d(TAG, "Failed to find statsd when logging event");
@@ -151,7 +151,7 @@ public final class StatsLog extends StatsLogInternal {
@NonNull long[] experimentIds) {
synchronized (sLogLock) {
try {
- IStatsManager service = getIStatsManagerLocked();
+ IStatsd service = getIStatsdLocked();
if (service == null) {
if (DEBUG) {
Slog.d(TAG, "Failed to find statsd when logging event");
@@ -191,7 +191,7 @@ public final class StatsLog extends StatsLogInternal {
long packageVersionCode, int rollbackReason, String failingPackageName) {
synchronized (sLogLock) {
try {
- IStatsManager service = getIStatsManagerLocked();
+ IStatsd service = getIStatsdLocked();
if (service == null) {
if (DEBUG) {
Slog.d(TAG, "Failed to find statsd when logging event");
@@ -215,11 +215,11 @@ public final class StatsLog extends StatsLogInternal {
}
- private static IStatsManager getIStatsManagerLocked() throws RemoteException {
+ private static IStatsd getIStatsdLocked() throws RemoteException {
if (sService != null) {
return sService;
}
- sService = IStatsManager.Stub.asInterface(ServiceManager.getService("stats"));
+ sService = IStatsd.Stub.asInterface(ServiceManager.getService("stats"));
return sService;
}
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index ba2509302094..117b971ad446 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -21,6 +21,7 @@ import static android.Manifest.permission.CONFIGURE_DISPLAY_COLOR_MODE;
import android.annotation.IntDef;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
import android.app.KeyguardManager;
@@ -857,6 +858,31 @@ public final class Display {
}
/**
+ * <p> Returns true if the connected display can be switched into a mode with minimal
+ * post processing. </p>
+ *
+ * <p> If the Display sink is connected via HDMI, this method will return true if the
+ * display supports either Auto Low Latency Mode or Game Content Type.
+ *
+ * <p> If the Display sink has an internal connection or uses some other protocol than
+ * HDMI, this method will return true if the sink can be switched into an
+ * implementation-defined low latency image processing mode. </p>
+ *
+ * <p> The ability to switch to a mode with minimal post processing may be disabled
+ * by a user setting in the system settings menu. In that case, this method returns
+ * false. </p>
+ *
+ * @see android.view.Window#setPreferMinimalPostProcessing
+ */
+ @SuppressLint("VisiblySynchronized")
+ public boolean isMinimalPostProcessingSupported() {
+ synchronized (this) {
+ updateDisplayInfoLocked();
+ return mDisplayInfo.minimalPostProcessingSupported;
+ }
+ }
+
+ /**
* Request the display applies a color mode.
* @hide
*/
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index 04e82c72da89..b84a7b5b9d98 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -184,6 +184,14 @@ public final class DisplayInfo implements Parcelable {
public Display.HdrCapabilities hdrCapabilities;
/**
+ * Indicates whether the display can be switched into a mode with minimal post
+ * processing.
+ *
+ * @see android.view.Display#isMinimalPostProcessingSupported
+ */
+ public boolean minimalPostProcessingSupported;
+
+ /**
* The logical display density which is the basis for density-independent
* pixels.
*/
@@ -305,6 +313,7 @@ public final class DisplayInfo implements Parcelable {
&& colorMode == other.colorMode
&& Arrays.equals(supportedColorModes, other.supportedColorModes)
&& Objects.equals(hdrCapabilities, other.hdrCapabilities)
+ && minimalPostProcessingSupported == other.minimalPostProcessingSupported
&& logicalDensityDpi == other.logicalDensityDpi
&& physicalXDpi == other.physicalXDpi
&& physicalYDpi == other.physicalYDpi
@@ -346,6 +355,7 @@ public final class DisplayInfo implements Parcelable {
supportedColorModes = Arrays.copyOf(
other.supportedColorModes, other.supportedColorModes.length);
hdrCapabilities = other.hdrCapabilities;
+ minimalPostProcessingSupported = other.minimalPostProcessingSupported;
logicalDensityDpi = other.logicalDensityDpi;
physicalXDpi = other.physicalXDpi;
physicalYDpi = other.physicalYDpi;
@@ -388,6 +398,7 @@ public final class DisplayInfo implements Parcelable {
supportedColorModes[i] = source.readInt();
}
hdrCapabilities = source.readParcelable(null);
+ minimalPostProcessingSupported = source.readBoolean();
logicalDensityDpi = source.readInt();
physicalXDpi = source.readFloat();
physicalYDpi = source.readFloat();
@@ -430,6 +441,7 @@ public final class DisplayInfo implements Parcelable {
dest.writeInt(supportedColorModes[i]);
}
dest.writeParcelable(hdrCapabilities, flags);
+ dest.writeBoolean(minimalPostProcessingSupported);
dest.writeInt(logicalDensityDpi);
dest.writeFloat(physicalXDpi);
dest.writeFloat(physicalYDpi);
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index b829c9f36f84..9496827b1a84 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -44,6 +44,7 @@ import android.view.RemoteAnimationAdapter;
import android.view.IRotationWatcher;
import android.view.ISystemGestureExclusionListener;
import android.view.IWallpaperVisibilityListener;
+import android.view.IWindow;
import android.view.IWindowSession;
import android.view.IWindowSessionCallback;
import android.view.KeyEvent;
@@ -120,6 +121,17 @@ interface IWindowManager
void setDisplayWindowRotationController(IDisplayWindowRotationController controller);
/**
+ * Adds a root container that a client shell can populate with its own windows (usually via
+ * WindowlessWindowManager).
+ *
+ * @param client an IWindow used for window-level communication (ime, finish draw, etc.).
+ * @param windowType used by WM to determine the z-order. This is the same as the window type
+ * used in {@link WindowManager.LayoutParams}.
+ * @return a SurfaceControl to add things to.
+ */
+ SurfaceControl addShellRoot(int displayId, IWindow client, int windowType);
+
+ /**
* Like overridePendingAppTransitionMultiThumb, but uses a future to supply the specs. This is
* used for recents, where generating the thumbnails of the specs takes a non-trivial amount of
* time, so we want to move that off the critical path for starting the new activity.
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 87628da42599..db83ededfdec 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -170,6 +170,8 @@ public final class SurfaceControl implements Parcelable {
private static native int nativeGetActiveColorMode(IBinder displayToken);
private static native boolean nativeSetActiveColorMode(IBinder displayToken,
int colorMode);
+ private static native void nativeSetAutoLowLatencyMode(IBinder displayToken, boolean on);
+ private static native void nativeSetGameContentType(IBinder displayToken, boolean on);
private static native void nativeSetDisplayPowerMode(
IBinder displayToken, int mode);
private static native void nativeDeferTransactionUntil(long transactionObj, long nativeObject,
@@ -187,6 +189,9 @@ public final class SurfaceControl implements Parcelable {
private static native Display.HdrCapabilities nativeGetHdrCapabilities(IBinder displayToken);
+ private static native boolean nativeGetAutoLowLatencyModeSupport(IBinder displayToken);
+ private static native boolean nativeGetGameContentTypeSupport(IBinder displayToken);
+
private static native void nativeSetInputWindowInfo(long transactionObj, long nativeObject,
InputWindowHandle handle);
@@ -1670,6 +1675,28 @@ public final class SurfaceControl implements Parcelable {
/**
* @hide
*/
+ public static void setAutoLowLatencyMode(IBinder displayToken, boolean on) {
+ if (displayToken == null) {
+ throw new IllegalArgumentException("displayToken must not be null");
+ }
+
+ nativeSetAutoLowLatencyMode(displayToken, on);
+ }
+
+ /**
+ * @hide
+ */
+ public static void setGameContentType(IBinder displayToken, boolean on) {
+ if (displayToken == null) {
+ throw new IllegalArgumentException("displayToken must not be null");
+ }
+
+ nativeSetGameContentType(displayToken, on);
+ }
+
+ /**
+ * @hide
+ */
@UnsupportedAppUsage
public static void setDisplayProjection(IBinder displayToken,
int orientation, Rect layerStackRect, Rect displayRect) {
@@ -1721,6 +1748,28 @@ public final class SurfaceControl implements Parcelable {
/**
* @hide
*/
+ public static boolean getAutoLowLatencyModeSupport(IBinder displayToken) {
+ if (displayToken == null) {
+ throw new IllegalArgumentException("displayToken must not be null");
+ }
+
+ return nativeGetAutoLowLatencyModeSupport(displayToken);
+ }
+
+ /**
+ * @hide
+ */
+ public static boolean getGameContentTypeSupport(IBinder displayToken) {
+ if (displayToken == null) {
+ throw new IllegalArgumentException("displayToken must not be null");
+ }
+
+ return nativeGetGameContentTypeSupport(displayToken);
+ }
+
+ /**
+ * @hide
+ */
@UnsupportedAppUsage
public static IBinder createDisplay(String name, boolean secure) {
if (name == null) {
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index d79abc207bfd..a168c07e7409 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -1197,6 +1197,44 @@ public abstract class Window {
}
/**
+ * If {@code isPreferred} is true, this method requests that the connected display does minimal
+ * post processing when this window is visible on the screen. Otherwise, it requests that the
+ * display switches back to standard image processing.
+ *
+ * <p> By default, the display does not do minimal post processing and if this is desired, this
+ * method should not be used. It should be used with {@code isPreferred=true} when low
+ * latency has a higher priority than image enhancement processing (e.g. for games or video
+ * conferencing). The display will automatically go back into standard image processing mode
+ * when no window requesting minimal posst processing is visible on screen anymore.
+ * {@code setPreferMinimalPostProcessing(false)} can be used if
+ * {@code setPreferMinimalPostProcessing(true)} was previously called for this window and
+ * minimal post processing is no longer required.
+ *
+ * <p>If the Display sink is connected via HDMI, the device will begin to send infoframes with
+ * Auto Low Latency Mode enabled and Game Content Type. This will switch the connected display
+ * to a minimal image processing mode (if available), which reduces latency, improving the user
+ * experience for gaming or video conferencing applications. For more information, see HDMI 2.1
+ * specification.
+ *
+ * <p>If the Display sink has an internal connection or uses some other protocol than HDMI,
+ * effects may be similar but implementation-defined.
+ *
+ * <p>The ability to switch to a mode with minimal post proessing may be disabled by a user
+ * setting in the system settings menu. In that case, this method does nothing.
+ *
+ * @see android.content.pm.ActivityInfo#preferMinimalPostProcessing
+ * @see android.view.Display#isMinimalPostProcessingSupported
+ * @see android.view.WindowManager.LayoutParams#preferMinimalPostProcessing
+ *
+ * @param isPreferred Indicates whether minimal post processing is preferred for this window
+ * ({@code isPreferred=true}) or not ({@code isPreferred=false}).
+ */
+ public void setPreferMinimalPostProcessing(boolean isPreferred) {
+ mWindowAttributes.preferMinimalPostProcessing = isPreferred;
+ dispatchWindowAttributesChanged(mWindowAttributes);
+ }
+
+ /**
* Returns the requested color mode of the window, one of
* {@link ActivityInfo#COLOR_MODE_DEFAULT}, {@link ActivityInfo#COLOR_MODE_WIDE_COLOR_GAMUT}
* or {@link ActivityInfo#COLOR_MODE_HDR}. If {@link ActivityInfo#COLOR_MODE_WIDE_COLOR_GAMUT}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 9d5f98e4a24c..cbfe52bb387d 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -2573,6 +2573,33 @@ public interface WindowManager extends ViewManager {
public long hideTimeoutMilliseconds = -1;
/**
+ * Indicates whether this window wants the connected display to do minimal post processing
+ * on the produced image or video frames. This will only be requested if the window is
+ * visible on the screen.
+ *
+ * <p>This setting should be used when low latency has a higher priority than image
+ * enhancement processing (e.g. for games or video conferencing).
+ *
+ * <p>If the Display sink is connected via HDMI, the device will begin to send infoframes
+ * with Auto Low Latency Mode enabled and Game Content Type. This will switch the connected
+ * display to a minimal image processing mode (if available), which reduces latency,
+ * improving the user experience for gaming or video conferencing applications. For more
+ * information, see HDMI 2.1 specification.
+ *
+ * <p>If the Display sink has an internal connection or uses some other protocol than HDMI,
+ * effects may be similar but implementation-defined.
+ *
+ * <p>The ability to switch to a mode with minimal post proessing may be disabled by a user
+ * setting in the system settings menu. In that case, this field is ignored and the display
+ * will remain in its current mode.
+ *
+ * @see android.content.pm.ActivityInfo#preferMinimalPostProcessing
+ * @see android.view.Display#isMinimalPostProcessingSupported
+ * @see android.view.Window#setPreferMinimalPostProcessing
+ */
+ public boolean preferMinimalPostProcessing = false;
+
+ /**
* The color mode requested by this window. The target display may
* not be able to honor the request. When the color mode is not set
* to {@link ActivityInfo#COLOR_MODE_DEFAULT}, it might override the
@@ -2754,6 +2781,7 @@ public interface WindowManager extends ViewManager {
out.writeLong(hideTimeoutMilliseconds);
out.writeInt(insetsFlags.appearance);
out.writeInt(insetsFlags.behavior);
+ out.writeBoolean(preferMinimalPostProcessing);
}
public static final @android.annotation.NonNull Parcelable.Creator<LayoutParams> CREATOR
@@ -2811,6 +2839,7 @@ public interface WindowManager extends ViewManager {
hideTimeoutMilliseconds = in.readLong();
insetsFlags.appearance = in.readInt();
insetsFlags.behavior = in.readInt();
+ preferMinimalPostProcessing = in.readBoolean();
}
@SuppressWarnings({"PointlessBitwiseExpression"})
@@ -2856,6 +2885,8 @@ public interface WindowManager extends ViewManager {
public static final int COLOR_MODE_CHANGED = 1 << 26;
/** {@hide} */
public static final int INSET_FLAGS_CHANGED = 1 << 27;
+ /** {@hide} */
+ public static final int MINIMAL_POST_PROCESSING_PREFERENCE_CHANGED = 1 << 28;
// internal buffer to backup/restore parameters under compatibility mode.
private int[] mCompatibilityParamsBackup = null;
@@ -3036,6 +3067,11 @@ public interface WindowManager extends ViewManager {
changes |= COLOR_MODE_CHANGED;
}
+ if (preferMinimalPostProcessing != o.preferMinimalPostProcessing) {
+ preferMinimalPostProcessing = o.preferMinimalPostProcessing;
+ changes |= MINIMAL_POST_PROCESSING_PREFERENCE_CHANGED;
+ }
+
// This can't change, it's only set at window creation time.
hideTimeoutMilliseconds = o.hideTimeoutMilliseconds;
@@ -3175,6 +3211,10 @@ public interface WindowManager extends ViewManager {
if (mColorMode != COLOR_MODE_DEFAULT) {
sb.append(" colorMode=").append(ActivityInfo.colorModeToString(mColorMode));
}
+ if (preferMinimalPostProcessing) {
+ sb.append(" preferMinimalPostProcessing=");
+ sb.append(preferMinimalPostProcessing);
+ }
sb.append(System.lineSeparator());
sb.append(prefix).append(" fl=").append(
ViewDebug.flagsToString(LayoutParams.class, "flags", flags));
diff --git a/core/java/android/view/accessibility/AccessibilityCache.java b/core/java/android/view/accessibility/AccessibilityCache.java
index dc8bf9b5fbae..9ab2c2b8bcb1 100644
--- a/core/java/android/view/accessibility/AccessibilityCache.java
+++ b/core/java/android/view/accessibility/AccessibilityCache.java
@@ -69,6 +69,8 @@ public class AccessibilityCache {
private long mAccessibilityFocus = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
private long mInputFocus = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
+ private int mAccessibilityFocusedWindow = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
+
private boolean mIsAllWindowsCached;
// The SparseArray of all {@link AccessibilityWindowInfo}s on all displays.
@@ -164,16 +166,19 @@ public class AccessibilityCache {
switch (eventType) {
case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: {
if (mAccessibilityFocus != AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
- refreshCachedNodeLocked(event.getWindowId(), mAccessibilityFocus);
+ refreshCachedNodeLocked(mAccessibilityFocusedWindow, mAccessibilityFocus);
}
mAccessibilityFocus = event.getSourceNodeId();
- refreshCachedNodeLocked(event.getWindowId(), mAccessibilityFocus);
+ mAccessibilityFocusedWindow = event.getWindowId();
+ refreshCachedNodeLocked(mAccessibilityFocusedWindow, mAccessibilityFocus);
} break;
case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: {
- if (mAccessibilityFocus == event.getSourceNodeId()) {
- refreshCachedNodeLocked(event.getWindowId(), mAccessibilityFocus);
+ if (mAccessibilityFocus == event.getSourceNodeId()
+ && mAccessibilityFocusedWindow == event.getWindowId()) {
+ refreshCachedNodeLocked(mAccessibilityFocusedWindow, mAccessibilityFocus);
mAccessibilityFocus = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
+ mAccessibilityFocusedWindow = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
}
} break;
@@ -210,6 +215,13 @@ public class AccessibilityCache {
} break;
case AccessibilityEvent.TYPE_WINDOWS_CHANGED:
+ if (event.getWindowChanges()
+ == AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED) {
+ // Don't need to clear all cache. Unless the changes are related to
+ // content, we won't clear all cache here.
+ refreshCachedWindowLocked(event.getWindowId());
+ break;
+ }
case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED: {
clear();
} break;
@@ -243,6 +255,34 @@ public class AccessibilityCache {
clearSubTreeLocked(windowId, sourceId);
}
+ private void refreshCachedWindowLocked(int windowId) {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "Refreshing cached window.");
+ }
+
+ if (windowId == AccessibilityWindowInfo.UNDEFINED_WINDOW_ID) {
+ return;
+ }
+
+ final int displayCounts = mWindowCacheByDisplay.size();
+ for (int i = 0; i < displayCounts; i++) {
+ final SparseArray<AccessibilityWindowInfo> windowsOfDisplay =
+ mWindowCacheByDisplay.valueAt(i);
+ if (windowsOfDisplay == null) {
+ continue;
+ }
+ final AccessibilityWindowInfo window = windowsOfDisplay.get(windowId);
+ if (window == null) {
+ continue;
+ }
+ if (!mAccessibilityNodeRefresher.refreshWindow(window)) {
+ // If we fail to refresh the window, clear all windows.
+ clearWindowCacheLocked();
+ }
+ return;
+ }
+ }
+
/**
* Gets a cached {@link AccessibilityNodeInfo} given the id of the hosting
* window and the accessibility id of the node.
@@ -413,8 +453,10 @@ public class AccessibilityCache {
refreshCachedNodeLocked(windowId, mAccessibilityFocus);
}
mAccessibilityFocus = sourceId;
+ mAccessibilityFocusedWindow = windowId;
} else if (mAccessibilityFocus == sourceId) {
mAccessibilityFocus = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
+ mAccessibilityFocusedWindow = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
}
if (clone.isFocused()) {
mInputFocus = sourceId;
@@ -439,6 +481,8 @@ public class AccessibilityCache {
mAccessibilityFocus = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
mInputFocus = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
+
+ mAccessibilityFocusedWindow = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
}
}
@@ -653,8 +697,14 @@ public class AccessibilityCache {
// Layer of indirection included to break dependency chain for testing
public static class AccessibilityNodeRefresher {
+ /** Refresh the given AccessibilityNodeInfo object. */
public boolean refreshNode(AccessibilityNodeInfo info, boolean bypassCache) {
return info.refresh(null, bypassCache);
}
+
+ /** Refresh the given AccessibilityWindowInfo object. */
+ public boolean refreshWindow(AccessibilityWindowInfo info) {
+ return info.refresh();
+ }
}
}
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index bb10ef10d79e..386651731d45 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -223,19 +223,36 @@ public final class AccessibilityInteractionClient
* @return The {@link AccessibilityWindowInfo}.
*/
public AccessibilityWindowInfo getWindow(int connectionId, int accessibilityWindowId) {
+ return getWindow(connectionId, accessibilityWindowId, /* bypassCache */ false);
+ }
+
+ /**
+ * Gets the info for a window.
+ *
+ * @param connectionId The id of a connection for interacting with the system.
+ * @param accessibilityWindowId A unique window id. Use
+ * {@link android.view.accessibility.AccessibilityWindowInfo#ACTIVE_WINDOW_ID}
+ * to query the currently active window.
+ * @param bypassCache Whether to bypass the cache.
+ * @return The {@link AccessibilityWindowInfo}.
+ */
+ public AccessibilityWindowInfo getWindow(int connectionId, int accessibilityWindowId,
+ boolean bypassCache) {
try {
IAccessibilityServiceConnection connection = getConnection(connectionId);
if (connection != null) {
- AccessibilityWindowInfo window = sAccessibilityCache.getWindow(
- accessibilityWindowId);
- if (window != null) {
+ AccessibilityWindowInfo window;
+ if (!bypassCache) {
+ window = sAccessibilityCache.getWindow(accessibilityWindowId);
+ if (window != null) {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "Window cache hit");
+ }
+ return window;
+ }
if (DEBUG) {
- Log.i(LOG_TAG, "Window cache hit");
+ Log.i(LOG_TAG, "Window cache miss");
}
- return window;
- }
- if (DEBUG) {
- Log.i(LOG_TAG, "Window cache miss");
}
final long identityToken = Binder.clearCallingIdentity();
try {
@@ -244,7 +261,9 @@ public final class AccessibilityInteractionClient
Binder.restoreCallingIdentity(identityToken);
}
if (window != null) {
- sAccessibilityCache.addWindow(window);
+ if (!bypassCache) {
+ sAccessibilityCache.addWindow(window);
+ }
return window;
}
} else {
diff --git a/core/java/android/view/accessibility/AccessibilityWindowInfo.java b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
index 2cc6e9aebd74..ca5c417bdc6d 100644
--- a/core/java/android/view/accessibility/AccessibilityWindowInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
@@ -87,6 +87,8 @@ public final class AccessibilityWindowInfo implements Parcelable {
/** @hide */
public static final int ACTIVE_WINDOW_ID = Integer.MAX_VALUE;
/** @hide */
+ public static final int UNDEFINED_CONNECTION_ID = -1;
+ /** @hide */
public static final int UNDEFINED_WINDOW_ID = -1;
/** @hide */
public static final int ANY_WINDOW_ID = -2;
@@ -117,7 +119,7 @@ public final class AccessibilityWindowInfo implements Parcelable {
private CharSequence mTitle;
private long mAnchorId = AccessibilityNodeInfo.UNDEFINED_NODE_ID;
- private int mConnectionId = UNDEFINED_WINDOW_ID;
+ private int mConnectionId = UNDEFINED_CONNECTION_ID;
/**
* Creates a new {@link AccessibilityWindowInfo}.
@@ -539,6 +541,30 @@ public final class AccessibilityWindowInfo implements Parcelable {
}
}
+ /**
+ * Refreshes this window with the latest state of the window it represents.
+ * <p>
+ * <strong>Note:</strong> If this method returns false this info is obsolete
+ * since it represents a window that is no longer exist.
+ * </p>
+ *
+ * @hide
+ */
+ public boolean refresh() {
+ if (mConnectionId == UNDEFINED_CONNECTION_ID || mId == UNDEFINED_WINDOW_ID) {
+ return false;
+ }
+ final AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
+ final AccessibilityWindowInfo refreshedInfo = client.getWindow(mConnectionId,
+ mId, /* bypassCache */true);
+ if (refreshedInfo == null) {
+ return false;
+ }
+ init(refreshedInfo);
+ refreshedInfo.recycle();
+ return true;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -586,6 +612,7 @@ public final class AccessibilityWindowInfo implements Parcelable {
mTitle = other.mTitle;
mAnchorId = other.mAnchorId;
+ if (mChildIds != null) mChildIds.clear();
if (other.mChildIds != null && other.mChildIds.size() > 0) {
if (mChildIds == null) {
mChildIds = other.mChildIds.clone();
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 7cec440dd80b..c571737cec8f 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -3473,10 +3473,18 @@ public class RemoteViews implements Parcelable, Filter {
return applyAsync(context, parent, executor, listener, null);
}
+ private CancellationSignal startTaskOnExecutor(AsyncApplyTask task, Executor executor) {
+ CancellationSignal cancelSignal = new CancellationSignal();
+ cancelSignal.setOnCancelListener(task);
+
+ task.executeOnExecutor(executor == null ? AsyncTask.THREAD_POOL_EXECUTOR : executor);
+ return cancelSignal;
+ }
+
/** @hide */
public CancellationSignal applyAsync(Context context, ViewGroup parent,
Executor executor, OnViewAppliedListener listener, OnClickHandler handler) {
- return getAsyncApplyTask(context, parent, listener, handler).startTaskOnExecutor(executor);
+ return startTaskOnExecutor(getAsyncApplyTask(context, parent, listener, handler), executor);
}
private AsyncApplyTask getAsyncApplyTask(Context context, ViewGroup parent,
@@ -3487,7 +3495,6 @@ public class RemoteViews implements Parcelable, Filter {
private class AsyncApplyTask extends AsyncTask<Void, Void, ViewTree>
implements CancellationSignal.OnCancelListener {
- final CancellationSignal mCancelSignal = new CancellationSignal();
final RemoteViews mRV;
final ViewGroup mParent;
final Context mContext;
@@ -3538,7 +3545,6 @@ public class RemoteViews implements Parcelable, Filter {
@Override
protected void onPostExecute(ViewTree viewTree) {
- mCancelSignal.setOnCancelListener(null);
if (mError == null) {
if (mListener != null) {
mListener.onViewInflated(viewTree.mRoot);
@@ -3575,13 +3581,6 @@ public class RemoteViews implements Parcelable, Filter {
@Override
public void onCancel() {
cancel(true);
- mCancelSignal.setOnCancelListener(null);
- }
-
- private CancellationSignal startTaskOnExecutor(Executor executor) {
- mCancelSignal.setOnCancelListener(this);
- executeOnExecutor(executor == null ? AsyncTask.THREAD_POOL_EXECUTOR : executor);
- return mCancelSignal;
}
}
@@ -3647,8 +3646,8 @@ public class RemoteViews implements Parcelable, Filter {
}
}
- return new AsyncApplyTask(rvToApply, (ViewGroup) v.getParent(),
- context, listener, handler, v).startTaskOnExecutor(executor);
+ return startTaskOnExecutor(new AsyncApplyTask(rvToApply, (ViewGroup) v.getParent(),
+ context, listener, handler, v), executor);
}
private void performApply(View v, ViewGroup parent, OnClickHandler handler) {
diff --git a/core/java/com/android/internal/app/AbstractResolverComparator.java b/core/java/com/android/internal/app/AbstractResolverComparator.java
index bb7e4d5114ba..eb746127a351 100644
--- a/core/java/com/android/internal/app/AbstractResolverComparator.java
+++ b/core/java/com/android/internal/app/AbstractResolverComparator.java
@@ -263,6 +263,7 @@ public abstract class AbstractResolverComparator implements Comparator<ResolvedC
mHandler.removeMessages(RANKER_SERVICE_RESULT);
mHandler.removeMessages(RANKER_RESULT_TIMEOUT);
afterCompute();
+ mAfterCompute = null;
}
private boolean isDefaultBrowser(ResolveInfo ri) {
diff --git a/core/java/com/android/internal/app/ISoundTriggerService.aidl b/core/java/com/android/internal/app/ISoundTriggerService.aidl
index ea24d5fbb2f7..d94294f0aa22 100644
--- a/core/java/com/android/internal/app/ISoundTriggerService.aidl
+++ b/core/java/com/android/internal/app/ISoundTriggerService.aidl
@@ -20,6 +20,7 @@ import android.app.PendingIntent;
import android.content.ComponentName;
import android.hardware.soundtrigger.IRecognitionStatusCallback;
import android.hardware.soundtrigger.SoundTrigger;
+import android.hardware.soundtrigger.ModelParams;
import android.os.Bundle;
import android.os.ParcelUuid;
@@ -56,4 +57,16 @@ interface ISoundTriggerService {
int getModelState(in ParcelUuid soundModelId);
@nullable SoundTrigger.ModuleProperties getModuleProperties();
+
+ int setParameter(in ParcelUuid soundModelId, in ModelParams modelParam,
+ int value);
+
+ /**
+ * @throws UnsupportedOperationException if hal or model do not support this API.
+ * @throws IllegalArgumentException if invalid model handle or parameter is passed.
+ */
+ int getParameter(in ParcelUuid soundModelId, in ModelParams modelParam);
+
+ @nullable SoundTrigger.ModelParamRange queryParameter(in ParcelUuid soundModelId,
+ in ModelParams modelParam);
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index bc44fcf3691d..d0a83c4369a6 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -16,6 +16,9 @@
package com.android.internal.os;
+import static android.os.BatteryStatsManager.NUM_WIFI_STATES;
+import static android.os.BatteryStatsManager.NUM_WIFI_SUPPL_STATES;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UnsupportedAppUsage;
@@ -5267,7 +5270,7 @@ public class BatteryStatsImpl extends BatteryStats {
// Unknown is included in DATA_CONNECTION_OTHER.
int bin = DATA_CONNECTION_OUT_OF_SERVICE;
if (hasData) {
- if (dataType > 0 && dataType <= TelephonyManager.MAX_NETWORK_TYPE) {
+ if (dataType > 0 && dataType <= TelephonyManager.getAllNetworkTypes().length) {
bin = dataType;
} else {
switch (serviceType) {
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 3f05c3b57c69..fa64fd10d6db 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -7,7 +7,6 @@
#include "SkAndroidCodec.h"
#include "SkBRDAllocator.h"
#include "SkFrontBufferedStream.h"
-#include "SkMakeUnique.h"
#include "SkMath.h"
#include "SkPixelRef.h"
#include "SkStream.h"
@@ -586,7 +585,7 @@ static jobject nativeDecodeAsset(JNIEnv* env, jobject clazz, jlong native_asset,
Asset* asset = reinterpret_cast<Asset*>(native_asset);
// since we know we'll be done with the asset when we return, we can
// just use a simple wrapper
- return doDecode(env, skstd::make_unique<AssetStreamAdaptor>(asset), padding, options,
+ return doDecode(env, std::make_unique<AssetStreamAdaptor>(asset), padding, options,
inBitmapHandle, colorSpaceHandle);
}
@@ -594,7 +593,7 @@ static jobject nativeDecodeByteArray(JNIEnv* env, jobject, jbyteArray byteArray,
jint offset, jint length, jobject options, jlong inBitmapHandle, jlong colorSpaceHandle) {
AutoJavaByteArray ar(env, byteArray);
- return doDecode(env, skstd::make_unique<SkMemoryStream>(ar.ptr() + offset, length, false),
+ return doDecode(env, std::make_unique<SkMemoryStream>(ar.ptr() + offset, length, false),
nullptr, options, inBitmapHandle, colorSpaceHandle);
}
diff --git a/core/jni/android_hardware_SoundTrigger.cpp b/core/jni/android_hardware_SoundTrigger.cpp
index 0002f8b4048a..4376b0b4ac42 100644
--- a/core/jni/android_hardware_SoundTrigger.cpp
+++ b/core/jni/android_hardware_SoundTrigger.cpp
@@ -44,6 +44,13 @@ static struct {
jmethodID toString;
} gUUIDMethods;
+static const char* const kUnsupportedOperationExceptionClassPathName =
+ "java/lang/UnsupportedOperationException";
+static jclass gUnsupportedOperationExceptionClass;
+static const char* const kIllegalArgumentExceptionClassPathName =
+ "java/lang/IllegalArgumentException";
+static jclass gIllegalArgumentExceptionClass;
+
static const char* const kSoundTriggerClassPathName = "android/hardware/soundtrigger/SoundTrigger";
static jclass gSoundTriggerClass;
@@ -91,6 +98,11 @@ static struct {
jfieldID keyphrases;
} gKeyphraseSoundModelFields;
+static const char* const kModelParamRangeClassPathName =
+ "android/hardware/soundtrigger/SoundTrigger$ModelParamRange";
+static jclass gModelParamRangeClass;
+static jmethodID gModelParamRangeCstor;
+
static const char* const kRecognitionConfigClassPathName =
"android/hardware/soundtrigger/SoundTrigger$RecognitionConfig";
static jclass gRecognitionConfigClass;
@@ -164,6 +176,16 @@ enum {
SOUNDTRIGGER_EVENT_SERVICE_STATE_CHANGE = 4,
};
+static jint throwUnsupportedOperationException(JNIEnv *env)
+{
+ return env->ThrowNew(gUnsupportedOperationExceptionClass, nullptr);
+}
+
+static jint throwIllegalArgumentException(JNIEnv *env)
+{
+ return env->ThrowNew(gIllegalArgumentExceptionClass, nullptr);
+}
+
// ----------------------------------------------------------------------------
// ref-counted object for callbacks
class JNISoundTriggerCallback: public SoundTriggerCallback
@@ -822,6 +844,69 @@ android_hardware_SoundTrigger_getModelState(JNIEnv *env, jobject thiz,
return status;
}
+static jint
+android_hardware_SoundTrigger_setParameter(JNIEnv *env, jobject thiz,
+ jint jHandle, jint jModelParam, jint jValue)
+{
+ ALOGV("setParameter");
+ sp<SoundTrigger> module = getSoundTrigger(env, thiz);
+ if (module == NULL) {
+ return SOUNDTRIGGER_STATUS_NO_INIT;
+ }
+ return module->setParameter(jHandle, (sound_trigger_model_parameter_t) jModelParam, jValue);
+}
+
+static jint
+android_hardware_SoundTrigger_getParameter(JNIEnv *env, jobject thiz,
+ jint jHandle, jint jModelParam)
+{
+ ALOGV("getParameter");
+ sp<SoundTrigger> module = getSoundTrigger(env, thiz);
+ if (module == NULL) {
+ throwUnsupportedOperationException(env);
+ return -1;
+ }
+
+ jint nValue;
+ jint status = module->getParameter(jHandle,
+ (sound_trigger_model_parameter_t) jModelParam, &nValue);
+
+ switch (status) {
+ case 0:
+ return nValue;
+ case -EINVAL:
+ throwIllegalArgumentException(env);
+ break;
+ default:
+ throwUnsupportedOperationException(env);
+ break;
+ }
+
+ return -1;
+}
+
+static jobject
+android_hardware_SoundTrigger_queryParameter(JNIEnv *env, jobject thiz,
+ jint jHandle, jint jModelParam)
+{
+ ALOGV("queryParameter");
+ sp<SoundTrigger> module = getSoundTrigger(env, thiz);
+ if (module == nullptr) {
+ return nullptr;
+ }
+
+ sound_trigger_model_parameter_range_t nRange;
+ jint nValue = module->queryParameter(jHandle,
+ (sound_trigger_model_parameter_t) jModelParam, &nRange);
+
+ if (nValue != 0) {
+ ALOGE("failed to query parameter error code: %d", nValue);
+ return nullptr;
+ }
+
+ return env->NewObject(gModelParamRangeClass, gModelParamRangeCstor, nRange.start, nRange.end);
+}
+
static const JNINativeMethod gMethods[] = {
{"listModules",
"(Ljava/lang/String;Ljava/util/ArrayList;)I",
@@ -854,6 +939,15 @@ static const JNINativeMethod gModuleMethods[] = {
{"getModelState",
"(I)I",
(void *)android_hardware_SoundTrigger_getModelState},
+ {"setParameter",
+ "(III)I",
+ (void *)android_hardware_SoundTrigger_setParameter},
+ {"getParameter",
+ "(II)I",
+ (void *)android_hardware_SoundTrigger_getParameter},
+ {"queryParameter",
+ "(II)Landroid/hardware/soundtrigger/SoundTrigger$ModelParamRange;",
+ (void *)android_hardware_SoundTrigger_queryParameter}
};
int register_android_hardware_SoundTrigger(JNIEnv *env)
@@ -866,6 +960,12 @@ int register_android_hardware_SoundTrigger(JNIEnv *env)
gUUIDClass = MakeGlobalRefOrDie(env, uuidClass);
gUUIDMethods.toString = GetMethodIDOrDie(env, uuidClass, "toString", "()Ljava/lang/String;");
+ jclass exUClass = FindClassOrDie(env, kUnsupportedOperationExceptionClassPathName);
+ gUnsupportedOperationExceptionClass = MakeGlobalRefOrDie(env, exUClass);
+
+ jclass exIClass = FindClassOrDie(env, kIllegalArgumentExceptionClassPathName);
+ gIllegalArgumentExceptionClass = MakeGlobalRefOrDie(env, exIClass);
+
jclass lClass = FindClassOrDie(env, kSoundTriggerClassPathName);
gSoundTriggerClass = MakeGlobalRefOrDie(env, lClass);
@@ -906,6 +1006,10 @@ int register_android_hardware_SoundTrigger(JNIEnv *env)
"keyphrases",
"[Landroid/hardware/soundtrigger/SoundTrigger$Keyphrase;");
+ jclass modelParamRangeClass = FindClassOrDie(env, kModelParamRangeClassPathName);
+ gModelParamRangeClass = MakeGlobalRefOrDie(env, modelParamRangeClass);
+ gModelParamRangeCstor = GetMethodIDOrDie(env, modelParamRangeClass, "<init>", "(II)V");
+
jclass recognitionEventClass = FindClassOrDie(env, kRecognitionEventClassPathName);
gRecognitionEventClass = MakeGlobalRefOrDie(env, recognitionEventClass);
gRecognitionEventCstor = GetMethodIDOrDie(env, recognitionEventClass, "<init>",
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index c6e678ab50b0..ec8d4ab9985b 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -1199,6 +1199,34 @@ static jobject nativeGetHdrCapabilities(JNIEnv* env, jclass clazz, jobject token
capabilities.getDesiredMaxAverageLuminance(), capabilities.getDesiredMinLuminance());
}
+static jboolean nativeGetAutoLowLatencyModeSupport(JNIEnv* env, jclass clazz, jobject tokenObject) {
+ sp<IBinder> token(ibinderForJavaObject(env, tokenObject));
+ if (token == NULL) return NULL;
+
+ return SurfaceComposerClient::getAutoLowLatencyModeSupport(token);
+}
+
+static jboolean nativeGetGameContentTypeSupport(JNIEnv* env, jclass clazz, jobject tokenObject) {
+ sp<IBinder> token(ibinderForJavaObject(env, tokenObject));
+ if (token == NULL) return NULL;
+
+ return SurfaceComposerClient::getGameContentTypeSupport(token);
+}
+
+static void nativeSetAutoLowLatencyMode(JNIEnv* env, jclass clazz, jobject tokenObject, jboolean on) {
+ sp<IBinder> token(ibinderForJavaObject(env, tokenObject));
+ if (token == NULL) return;
+
+ SurfaceComposerClient::setAutoLowLatencyMode(token, on);
+}
+
+static void nativeSetGameContentType(JNIEnv* env, jclass clazz, jobject tokenObject, jboolean on) {
+ sp<IBinder> token(ibinderForJavaObject(env, tokenObject));
+ if (token == NULL) return;
+
+ SurfaceComposerClient::setGameContentType(token, on);
+}
+
static jlong nativeReadFromParcel(JNIEnv* env, jclass clazz, jobject parcelObj) {
Parcel* parcel = parcelForJavaObject(env, parcelObj);
if (parcel == NULL) {
@@ -1402,6 +1430,14 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
(void*)nativeGetActiveColorMode},
{"nativeSetActiveColorMode", "(Landroid/os/IBinder;I)Z",
(void*)nativeSetActiveColorMode},
+ {"nativeGetAutoLowLatencyModeSupport", "(Landroid/os/IBinder;)Z",
+ (void*)nativeGetAutoLowLatencyModeSupport },
+ {"nativeSetAutoLowLatencyMode", "(Landroid/os/IBinder;Z)V",
+ (void*)nativeSetAutoLowLatencyMode },
+ {"nativeGetGameContentTypeSupport", "(Landroid/os/IBinder;)Z",
+ (void*)nativeGetGameContentTypeSupport },
+ {"nativeSetGameContentType", "(Landroid/os/IBinder;Z)V",
+ (void*)nativeSetGameContentType },
{"nativeGetCompositionDataspaces", "()[I",
(void*)nativeGetCompositionDataspaces},
{"nativeGetHdrCapabilities", "(Landroid/os/IBinder;)Landroid/view/Display$HdrCapabilities;",
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 166cde0d7005..1025f81b2864 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -2494,6 +2494,30 @@
<enum name="hdr" value="2" />
</attr>
<attr name="forceQueryable" format="boolean" />
+ <!-- Indicates whether the activity wants the connected display to do minimal
+ post processing on the produced image or video frames. This will only be
+ requested if this activity's main window is visible on the screen.
+
+ <p> This setting should be used when low latency has a higher priority than
+ image enhancement processing (e.g. for games or video conferencing).
+
+ <p> If the Display sink is connected via HDMI, the device will begin to
+ send infoframes with Auto Low Latency Mode enabled and Game Content Type.
+ This will switch the connected display to a minimal image processing mode
+ (if available), which reduces latency, improving the user experience for
+ gaming or video conferencing applications. For more information,
+ see HDMI 2.1 specification.
+
+ <p> If the Display sink has an internal connection or uses some other
+ protocol than HDMI, effects may be similar but implementation-defined.
+
+ <p> The ability to switch to a mode with minimal post proessing may be
+ disabled by a user setting in the system settings menu. In that case,
+ this field is ignored and the display will remain in its current
+ mode.
+
+ <p> See {@link android.content.pm.ActivityInfo #preferMinimalPostProcessing} -->
+ <attr name="preferMinimalPostProcessing" format="boolean"/>
</declare-styleable>
<!-- The <code>activity-alias</code> tag declares a new
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index ced5deb66899..89c913b8f580 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2652,11 +2652,6 @@
<!-- Package name for default network scorer app; overridden by product overlays. -->
<string name="config_defaultNetworkScorerPackageName"></string>
- <!-- Feature flag to enable memory efficient task snapshots that are used in recents optimized
- for low memory devices and replace the app transition starting window with the splash
- screen. -->
- <bool name="config_lowRamTaskSnapshotsAndRecents">false</bool>
-
<!-- The amount to scale fullscreen snapshots for Overview and snapshot starting windows. -->
<item name="config_fullTaskSnapshotScale" format="float" type="dimen">1.0</item>
@@ -4188,15 +4183,15 @@
<!-- The default value used for RawContacts.ACCOUNT_NAME when contacts are inserted without this
column set. These contacts are stored locally on the device and will not be removed even
- if an android.account.Account with this name and type exists. A null string will be used
- if the value is left empty. When this is non-empty then config_rawContactsLocalAccountType
+ if no android.account.Account with this name exists. A null string will be used if the
+ value is left empty. When this is non-empty then config_rawContactsLocalAccountType
should also be non-empty. -->
<string name="config_rawContactsLocalAccountName" translatable="false"></string>
<!-- The default value used for RawContacts.ACCOUNT_TYPE when contacts are inserted without this
column set. These contacts are stored locally on the device and will not be removed even
- if an android.account.Account with this name and type exists. A null string will be used
- if the value is left empty. When this is non-empty then config_rawContactsLocalAccountName
+ if no android.account.Account with this type exists. A null string will be used if the
+ value is left empty. When this is non-empty then config_rawContactsLocalAccountName
should also be non-empty.-->
<string name="config_rawContactsLocalAccountType" translatable="false"></string>
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 78c4efec5b72..d753630f142a 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3051,6 +3051,10 @@
<public name="accessibilitySystemActionLockScreen" />
<public name="accessibilitySystemActionTakeScreenshot" />
</public-group>
+
+ <public-group type="attr" first-id="0x0101060c">
+ <public name="preferMinimalPostProcessing"/>
+ </public-group>
<!-- ===============================================================
DO NOT ADD UN-GROUPED ITEMS HERE
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 0f5da39a2c1e..de1b5baec4b2 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1011,53 +1011,32 @@
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_readContacts">read your contacts</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permdesc_readContacts" product="tablet">Allows the app to read
- data about your contacts stored on your tablet, including the frequency
- with which you\'ve called, emailed, or communicated in other ways with
- specific individuals. Apps will also have access to the accounts on your
- tablet that have created contacts. This may include accounts created by
- apps you have installed. This permission allows apps to save your contact
- data, and malicious apps may share contact data without your
- knowledge.</string>
+ <string name="permdesc_readContacts" product="tablet">Allows the app to read data about your contacts stored on your tablet.
+ Apps will also have access to the accounts on your tablet that have created contacts.
+ This may include accounts created by apps you have installed.
+ This permission allows apps to save your contact data, and malicious apps may share contact data without your knowledge.</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permdesc_readContacts" product="tv">Allows the app to read
- data about your contacts stored on your Android TV device, including the frequency
- with which you\'ve called, emailed, or communicated in other ways with
- specific individuals. Apps will also have access to the accounts on your
- Android TV device that have created contacts. This may include accounts
- created by apps you have installed. This permission allows apps to save
- your contact data, and malicious apps may share contact data without your
- knowledge.</string>
+ <string name="permdesc_readContacts" product="tv">Allows the app to read data about your contacts stored on your Android TV device.
+ Apps will also have access to the accounts on your Android TV device that have created contacts.
+ This may include accounts created by apps you have installed.
+ This permission allows apps to save your contact data, and malicious apps may share contact data without your knowledge.</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permdesc_readContacts" product="default">Allows the app to
- read data about your contacts stored on your phone, including the
- frequency with which you\'ve called, emailed, or communicated in other ways
- with specific individuals. Apps will also have access to the accounts
- on your phone that have created contacts. This may include accounts
- created by apps you have installed. This permission allows apps to
- save your contact data, and malicious apps may share contact data
- without your knowledge.</string>
+ <string name="permdesc_readContacts" product="default">Allows the app to read data about your contacts stored on your phone.
+ Apps will also have access to the accounts on your phone that have created contacts.
+ This may include accounts created by apps you have installed.
+ This permission allows apps to save your contact data, and malicious apps may share contact data without your knowledge.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_writeContacts">modify your contacts</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permdesc_writeContacts" product="tablet">Allows the app to
- modify the data about your contacts stored on your tablet, including the
- frequency with which you\'ve called, emailed, or communicated in other ways
- with specific contacts. This permission allows apps to delete contact
- data.</string>
+ <string name="permdesc_writeContacts" product="tablet">Allows the app to modify the data about your contacts stored on your tablet.
+ This permission allows apps to delete contact data.</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permdesc_writeContacts" product="tv">Allows the app to
- modify the data about your contacts stored on your Android TV device, including the
- frequency with which you\'ve called, emailed, or communicated in other ways
- with specific contacts. This permission allows apps to delete contact
- data.</string>
+ <string name="permdesc_writeContacts" product="tv">Allows the app to modify the data about your contacts stored on your Android TV device.
+ This permission allows apps to delete contact data.</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permdesc_writeContacts" product="default">Allows the app to
- modify the data about your contacts stored on your phone, including the
- frequency with which you\'ve called, emailed, or communicated in other ways
- with specific contacts. This permission allows apps to delete contact
- data.</string>
+ <string name="permdesc_writeContacts" product="default">Allows the app to modify the data about your contacts stored on your phone.
+ This permission allows apps to delete contact data.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_readCallLog">read call log</string>
@@ -1102,6 +1081,7 @@
<string name="permdesc_writeCalendar" product="default">This app can add, remove, or change calendar events on your phone. This app can send messages that may appear to come from calendar owners, or change events without notifying their owners.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the applicatfion to do this. -->
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_accessLocationExtraCommands">access extra location provider commands</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_accessLocationExtraCommands">Allows the app to access
@@ -1111,21 +1091,17 @@
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_accessFineLocation">access precise location only in the foreground</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permdesc_accessFineLocation">This app can get your exact location only when it is in the foreground. These location services must be turned on and available on your phone for the app to be able to use them. This may increase battery consumption.</string>
+ <string name="permdesc_accessFineLocation">This app can get your exact location only when it is in the foreground. Location services must be turned on and available on your device for the app to be able to use them. This may increase battery consumption.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permlab_accessCoarseLocation">access approximate location (network-based) only in the foreground</string>
- <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permdesc_accessCoarseLocation" product="tablet">This app can get your location based on network sources such as cell towers and Wi-Fi networks, but only when when the app is in the foreground. These location services must be turned on and available on your tablet for the app to be able to use them.</string>
- <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permdesc_accessCoarseLocation" product="tv">This app can get your location based on network sources such as cell towers and Wi-Fi networks, but only when when the app is in the foreground. These location services must be turned on and available on your Android TV device for the app to be able to use them.</string>
+ <string name="permlab_accessCoarseLocation">access approximate location only in the foreground</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permdesc_accessCoarseLocation" product="default">This app can get your location based on network sources such as cell towers and Wi-Fi networks, but only when the app is in the foreground. These location services must be turned on and available on your phone for the app to be able to use them.</string>
+ <string name="permdesc_accessCoarseLocation">This app can get your approximate location only when it is in the foreground. Location services must be turned on and available on your device for the app to be able to use them.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_accessBackgroundLocation">access location in the background</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permdesc_accessBackgroundLocation">If this is granted additionally to the approximate or precise location access the app can access the location while running in the background.</string>
+ <string name="permdesc_accessBackgroundLocation">This app can access location while running in the background, in addition to foreground location access.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_modifyAudioSettings">change your audio settings</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 29b92817c67a..9ad6bad2670c 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -357,7 +357,6 @@
<java-symbol type="bool" name="config_disableUsbPermissionDialogs"/>
<java-symbol type="dimen" name="config_fullTaskSnapshotScale" />
<java-symbol type="bool" name="config_use16BitTaskSnapshotPixelFormat" />
- <java-symbol type="bool" name="config_lowRamTaskSnapshotsAndRecents" />
<java-symbol type="bool" name="config_hasRecents" />
<java-symbol type="string" name="config_recentsComponentName" />
<java-symbol type="integer" name="config_minNumVisibleRecentTasks_lowRam" />
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java
index b906d84adf52..ed613c36b89b 100644
--- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java
+++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java
@@ -176,14 +176,12 @@ public class BluetoothTestUtils extends Assert {
mDevice.setPin(mPin);
break;
case BluetoothDevice.PAIRING_VARIANT_PASSKEY:
- mDevice.setPasskey(mPasskey);
break;
case BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION:
case BluetoothDevice.PAIRING_VARIANT_CONSENT:
mDevice.setPairingConfirmation(true);
break;
case BluetoothDevice.PAIRING_VARIANT_OOB_CONSENT:
- mDevice.setRemoteOutOfBandData();
break;
}
} else if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(intent.getAction())) {
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index c009f588f8a9..caae9088e9b5 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -24,6 +24,7 @@ android_test {
],
static_libs: [
"frameworks-base-testutils",
+ "core-test-rules", // for libcore.dalvik.system.CloseGuardSupport
"core-tests-support",
"android-common",
"frameworks-core-util-lib",
diff --git a/core/tests/coretests/src/android/provider/DeviceConfigTest.java b/core/tests/coretests/src/android/provider/DeviceConfigTest.java
index 8c1c3b569303..ae835e4a1c73 100644
--- a/core/tests/coretests/src/android/provider/DeviceConfigTest.java
+++ b/core/tests/coretests/src/android/provider/DeviceConfigTest.java
@@ -33,9 +33,6 @@ import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.util.HashMap;
-import java.util.Map;
-
/** Tests that ensure appropriate settings are backed up. */
@Presubmit
@RunWith(AndroidJUnit4.class)
@@ -488,22 +485,20 @@ public class DeviceConfigTest {
}
@Test
- public void setProperties() {
- Map<String, String> keyValues = new HashMap<>();
- keyValues.put(KEY, VALUE);
- keyValues.put(KEY2, VALUE2);
+ public void setProperties() throws DeviceConfig.BadConfigException {
+ Properties properties = new Properties.Builder(NAMESPACE).setString(KEY, VALUE)
+ .setString(KEY2, VALUE2).build();
- DeviceConfig.setProperties(new Properties(NAMESPACE, keyValues));
- Properties properties = DeviceConfig.getProperties(NAMESPACE);
+ DeviceConfig.setProperties(properties);
+ properties = DeviceConfig.getProperties(NAMESPACE);
assertThat(properties.getKeyset()).containsExactly(KEY, KEY2);
assertThat(properties.getString(KEY, DEFAULT_VALUE)).isEqualTo(VALUE);
assertThat(properties.getString(KEY2, DEFAULT_VALUE)).isEqualTo(VALUE2);
- Map<String, String> newKeyValues = new HashMap<>();
- newKeyValues.put(KEY, VALUE2);
- newKeyValues.put(KEY3, VALUE3);
+ properties = new Properties.Builder(NAMESPACE).setString(KEY, VALUE2)
+ .setString(KEY3, VALUE3).build();
- DeviceConfig.setProperties(new Properties(NAMESPACE, newKeyValues));
+ DeviceConfig.setProperties(properties);
properties = DeviceConfig.getProperties(NAMESPACE);
assertThat(properties.getKeyset()).containsExactly(KEY, KEY3);
assertThat(properties.getString(KEY, DEFAULT_VALUE)).isEqualTo(VALUE2);
@@ -514,18 +509,15 @@ public class DeviceConfigTest {
}
@Test
- public void setProperties_multipleNamespaces() {
- Map<String, String> keyValues = new HashMap<>();
- keyValues.put(KEY, VALUE);
- keyValues.put(KEY2, VALUE2);
-
- Map<String, String> keyValues2 = new HashMap<>();
- keyValues2.put(KEY2, VALUE);
- keyValues2.put(KEY3, VALUE2);
-
+ public void setProperties_multipleNamespaces() throws DeviceConfig.BadConfigException {
final String namespace2 = "namespace2";
- DeviceConfig.setProperties(new Properties(NAMESPACE, keyValues));
- DeviceConfig.setProperties(new Properties(namespace2, keyValues2));
+ Properties properties1 = new Properties.Builder(NAMESPACE).setString(KEY, VALUE)
+ .setString(KEY2, VALUE2).build();
+ Properties properties2 = new Properties.Builder(namespace2).setString(KEY2, VALUE)
+ .setString(KEY3, VALUE2).build();
+
+ DeviceConfig.setProperties(properties1);
+ DeviceConfig.setProperties(properties2);
Properties properties = DeviceConfig.getProperties(NAMESPACE);
assertThat(properties.getKeyset()).containsExactly(KEY, KEY2);
@@ -549,6 +541,26 @@ public class DeviceConfigTest {
deleteViaContentProvider(namespace2, KEY3);
}
+ @Test
+ public void propertiesBuilder() {
+ boolean booleanValue = true;
+ int intValue = 123;
+ float floatValue = 4.56f;
+ long longValue = -789L;
+ String key4 = "key4";
+ String key5 = "key5";
+
+ Properties properties = new Properties.Builder(NAMESPACE).setString(KEY, VALUE)
+ .setBoolean(KEY2, booleanValue).setInt(KEY3, intValue).setLong(key4, longValue)
+ .setFloat(key5, floatValue).build();
+ assertThat(properties.getNamespace()).isEqualTo(NAMESPACE);
+ assertThat(properties.getString(KEY, "defaultValue")).isEqualTo(VALUE);
+ assertThat(properties.getBoolean(KEY2, false)).isEqualTo(booleanValue);
+ assertThat(properties.getInt(KEY3, 0)).isEqualTo(intValue);
+ assertThat(properties.getLong("key4", 0L)).isEqualTo(longValue);
+ assertThat(properties.getFloat("key5", 0f)).isEqualTo(floatValue);
+ }
+
// TODO(mpape): resolve b/142727848 and re-enable listener tests
// @Test
// public void onPropertiesChangedListener_setPropertyCallback() throws InterruptedException {
diff --git a/core/tests/coretests/src/android/util/CloseGuardTest.java b/core/tests/coretests/src/android/util/CloseGuardTest.java
new file mode 100644
index 000000000000..d86c7b79fad6
--- /dev/null
+++ b/core/tests/coretests/src/android/util/CloseGuardTest.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2019 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 android.util;
+
+import libcore.dalvik.system.CloseGuardSupport;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+
+/** Unit tests for {@link android.util.CloseGuard} */
+public class CloseGuardTest {
+
+ @Rule
+ public final TestRule rule = CloseGuardSupport.getRule();
+
+ @Test
+ public void testEnabled_NotOpen() throws Throwable {
+ ResourceOwner owner = new ResourceOwner();
+ assertUnreleasedResources(owner, 0);
+ }
+
+ @Test
+ public void testEnabled_OpenNotClosed() throws Throwable {
+ ResourceOwner owner = new ResourceOwner();
+ owner.open();
+ assertUnreleasedResources(owner, 1);
+ }
+
+ @Test
+ public void testEnabled_OpenThenClosed() throws Throwable {
+ ResourceOwner owner = new ResourceOwner();
+ owner.open();
+ owner.close();
+ assertUnreleasedResources(owner, 0);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testOpen_withNullMethodName_throwsNPE() throws Throwable {
+ CloseGuard closeGuard = new CloseGuard();
+ closeGuard.open(null);
+ }
+
+ private void assertUnreleasedResources(ResourceOwner owner, int expectedCount)
+ throws Throwable {
+ try {
+ CloseGuardSupport.getFinalizerChecker().accept(owner, expectedCount);
+ } finally {
+ // Close the resource so that CloseGuard does not generate a warning for real when it
+ // is actually finalized.
+ owner.close();
+ }
+ }
+
+ /**
+ * A test user of {@link CloseGuard}.
+ */
+ private static class ResourceOwner {
+
+ private final CloseGuard mCloseGuard;
+
+ ResourceOwner() {
+ mCloseGuard = new CloseGuard();
+ }
+
+ public void open() {
+ mCloseGuard.open("close");
+ }
+
+ public void close() {
+ mCloseGuard.close();
+ }
+
+ /**
+ * Make finalize public so that it can be tested directly without relying on garbage
+ * collection to trigger it.
+ */
+ @Override
+ public void finalize() throws Throwable {
+ mCloseGuard.warnIfOpen();
+ super.finalize();
+ }
+ }
+}
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java
index 6bce6517a85d..0d5db6d791f1 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java
@@ -436,6 +436,22 @@ public class AccessibilityCacheTest {
}
@Test
+ public void windowsChangedWithWindowsChangeA11yFocusedEvent_dontClearCache() {
+ AccessibilityNodeInfo nodeInfo = getNodeWithA11yAndWindowId(SINGLE_VIEW_ID, WINDOW_ID_1);
+ mAccessibilityCache.add(nodeInfo);
+ AccessibilityEvent event = new AccessibilityEvent(AccessibilityEvent.TYPE_WINDOWS_CHANGED);
+ event.setWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED);
+ mAccessibilityCache.onAccessibilityEvent(event);
+ AccessibilityNodeInfo cachedNode = mAccessibilityCache.getNode(WINDOW_ID_1,
+ nodeInfo.getSourceNodeId());
+ try {
+ assertNotNull(cachedNode);
+ } finally {
+ nodeInfo.recycle();
+ }
+ }
+
+ @Test
public void subTreeChangeEvent_clearsNodeAndChild() {
AccessibilityEvent event = AccessibilityEvent
.obtain(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
diff --git a/graphics/java/android/graphics/FontFamily.java b/graphics/java/android/graphics/FontFamily.java
index 5ad93f411393..2648008b8f80 100644
--- a/graphics/java/android/graphics/FontFamily.java
+++ b/graphics/java/android/graphics/FontFamily.java
@@ -17,7 +17,6 @@
package android.graphics;
import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
import android.content.res.AssetManager;
import android.graphics.fonts.FontVariationAxis;
import android.text.TextUtils;
@@ -58,7 +57,6 @@ public class FontFamily {
*
* This cannot be deleted because it's in use by AndroidX.
*/
- @UnsupportedAppUsage(trackingBug = 123768928)
public long mNativePtr;
// Points native font family builder. Must be zero after freezing this family.
@@ -67,7 +65,6 @@ public class FontFamily {
/**
* This cannot be deleted because it's in use by AndroidX.
*/
- @UnsupportedAppUsage(trackingBug = 123768928)
public FontFamily() {
mBuilderPtr = nInitBuilder(null, 0);
mNativeBuilderCleaner = sBuilderRegistry.registerNativeAllocation(this, mBuilderPtr);
@@ -76,7 +73,6 @@ public class FontFamily {
/**
* This cannot be deleted because it's in use by AndroidX.
*/
- @UnsupportedAppUsage(trackingBug = 123768928)
public FontFamily(@Nullable String[] langs, int variant) {
final String langsString;
if (langs == null || langs.length == 0) {
@@ -98,7 +94,6 @@ public class FontFamily {
*
* This cannot be deleted because it's in use by AndroidX.
*/
- @UnsupportedAppUsage(trackingBug = 123768928)
public boolean freeze() {
if (mBuilderPtr == 0) {
throw new IllegalStateException("This FontFamily is already frozen");
@@ -115,7 +110,6 @@ public class FontFamily {
/**
* This cannot be deleted because it's in use by AndroidX.
*/
- @UnsupportedAppUsage(trackingBug = 123768928)
public void abortCreation() {
if (mBuilderPtr == 0) {
throw new IllegalStateException("This FontFamily is already frozen or abandoned");
@@ -127,7 +121,6 @@ public class FontFamily {
/**
* This cannot be deleted because it's in use by AndroidX.
*/
- @UnsupportedAppUsage(trackingBug = 123768928)
public boolean addFont(String path, int ttcIndex, FontVariationAxis[] axes, int weight,
int italic) {
if (mBuilderPtr == 0) {
@@ -151,7 +144,6 @@ public class FontFamily {
/**
* This cannot be deleted because it's in use by AndroidX.
*/
- @UnsupportedAppUsage(trackingBug = 123768928)
public boolean addFontFromBuffer(ByteBuffer font, int ttcIndex, FontVariationAxis[] axes,
int weight, int italic) {
if (mBuilderPtr == 0) {
@@ -179,7 +171,6 @@ public class FontFamily {
*
* This cannot be deleted because it's in use by AndroidX.
*/
- @UnsupportedAppUsage(trackingBug = 123768928)
public boolean addFontFromAssetManager(AssetManager mgr, String path, int cookie,
boolean isAsset, int ttcIndex, int weight, int isItalic,
FontVariationAxis[] axes) {
diff --git a/keystore/java/android/security/keystore/AttestationUtils.java b/keystore/java/android/security/keystore/AttestationUtils.java
index 94499ce24ed0..8a7b62332ffa 100644
--- a/keystore/java/android/security/keystore/AttestationUtils.java
+++ b/keystore/java/android/security/keystore/AttestationUtils.java
@@ -204,10 +204,7 @@ public abstract class AttestationUtils {
break;
}
case USE_INDIVIDUAL_ATTESTATION: {
- //TODO: Add the Keymaster tag for requesting the use of individual
- //attestation certificate, which should be
- //KeymasterDefs.KM_TAG_DEVICE_UNIQUE_ATTESTATION
- attestArgs.addBoolean(720);
+ attestArgs.addBoolean(KeymasterDefs.KM_TAG_DEVICE_UNIQUE_ATTESTATION);
break;
}
default:
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index c03e8e20175d..8de3e0a63815 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -18,6 +18,7 @@ package android.media;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
import android.media.audiopolicy.AudioProductStrategy;
@@ -178,6 +179,13 @@ public final class AudioAttributes implements Parcelable {
* utterances.
*/
public final static int USAGE_ASSISTANT = 16;
+ /**
+ * @hide
+ * Usage value to use for assistant voice interaction with remote caller on Cell and VoIP calls.
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public static final int USAGE_CALL_ASSISTANT = 17;
/**
* IMPORTANT: when adding new usage types, add them to SDK_USAGES and update SUPPRESSIBLE_USAGES
@@ -254,6 +262,7 @@ public final class AudioAttributes implements Parcelable {
SUPPRESSIBLE_USAGES.put(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE, SUPPRESSIBLE_MEDIA);
SUPPRESSIBLE_USAGES.put(USAGE_GAME, SUPPRESSIBLE_MEDIA);
SUPPRESSIBLE_USAGES.put(USAGE_ASSISTANT, SUPPRESSIBLE_MEDIA);
+ SUPPRESSIBLE_USAGES.put(USAGE_CALL_ASSISTANT, SUPPRESSIBLE_NEVER);
/** default volume assignment is STREAM_MUSIC, handle unknown usage as media */
SUPPRESSIBLE_USAGES.put(USAGE_UNKNOWN, SUPPRESSIBLE_MEDIA);
SUPPRESSIBLE_USAGES.put(USAGE_ASSISTANCE_SONIFICATION, SUPPRESSIBLE_SYSTEM);
@@ -682,6 +691,7 @@ public final class AudioAttributes implements Parcelable {
case USAGE_GAME:
case USAGE_VIRTUAL_SOURCE:
case USAGE_ASSISTANT:
+ case USAGE_CALL_ASSISTANT:
mUsage = usage;
break;
default:
@@ -1135,6 +1145,8 @@ public final class AudioAttributes implements Parcelable {
return new String("USAGE_GAME");
case USAGE_ASSISTANT:
return new String("USAGE_ASSISTANT");
+ case USAGE_CALL_ASSISTANT:
+ return new String("USAGE_CALL_ASSISTANT");
default:
return new String("unknown usage " + usage);
}
@@ -1238,6 +1250,7 @@ public final class AudioAttributes implements Parcelable {
case USAGE_ASSISTANCE_SONIFICATION:
return AudioSystem.STREAM_SYSTEM;
case USAGE_VOICE_COMMUNICATION:
+ case USAGE_CALL_ASSISTANT:
return AudioSystem.STREAM_VOICE_CALL;
case USAGE_VOICE_COMMUNICATION_SIGNALLING:
return fromGetVolumeControlStream ?
@@ -1302,6 +1315,7 @@ public final class AudioAttributes implements Parcelable {
USAGE_ASSISTANCE_SONIFICATION,
USAGE_GAME,
USAGE_ASSISTANT,
+ USAGE_CALL_ASSISTANT,
})
@Retention(RetentionPolicy.SOURCE)
public @interface AttributeUsage {}
diff --git a/media/java/android/media/soundtrigger/SoundTriggerManager.java b/media/java/android/media/soundtrigger/SoundTriggerManager.java
index dc400ad26eed..61b3e76e7cee 100644
--- a/media/java/android/media/soundtrigger/SoundTriggerManager.java
+++ b/media/java/android/media/soundtrigger/SoundTriggerManager.java
@@ -26,9 +26,11 @@ import android.annotation.SystemService;
import android.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
+import android.hardware.soundtrigger.ModelParams;
import android.hardware.soundtrigger.SoundTrigger;
import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel;
import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
+import android.hardware.soundtrigger.SoundTrigger.ModelParamRange;
import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
import android.hardware.soundtrigger.SoundTrigger.SoundModel;
import android.os.Bundle;
@@ -67,7 +69,7 @@ public final class SoundTriggerManager {
/**
* @hide
*/
- public SoundTriggerManager(Context context, ISoundTriggerService soundTriggerService ) {
+ public SoundTriggerManager(Context context, ISoundTriggerService soundTriggerService) {
if (DBG) {
Slog.i(TAG, "SoundTriggerManager created.");
}
@@ -89,14 +91,22 @@ public final class SoundTriggerManager {
}
/**
- * Returns the sound trigger model represented by the given UUID. An instance of {@link Model}
- * is returned.
+ * Get {@link SoundTriggerManager.Model} which is registered with the passed UUID
+ *
+ * @param soundModelId UUID associated with a loaded model
+ * @return {@link SoundTriggerManager.Model} associated with UUID soundModelId
*/
@RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
+ @Nullable
public Model getModel(UUID soundModelId) {
try {
- return new Model(mSoundTriggerService.getSoundModel(
- new ParcelUuid(soundModelId)));
+ GenericSoundModel model =
+ mSoundTriggerService.getSoundModel(new ParcelUuid(soundModelId));
+ if (model == null) {
+ return null;
+ }
+
+ return new Model(model);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -399,4 +409,80 @@ public final class SoundTriggerManager {
throw e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Set a model specific {@link ModelParams} with the given value. This
+ * parameter will keep its value for the duration the model is loaded regardless of starting and
+ * stopping recognition. Once the model is unloaded, the value will be lost.
+ * {@link SoundTriggerManager#queryParameter} should be checked first before calling this
+ * method.
+ *
+ * @param soundModelId UUID of model to apply the parameter value to.
+ * @param modelParam {@link ModelParams}
+ * @param value Value to set
+ * @return - {@link SoundTrigger#STATUS_OK} in case of success
+ * - {@link SoundTrigger#STATUS_NO_INIT} if the native service cannot be reached
+ * - {@link SoundTrigger#STATUS_BAD_VALUE} invalid input parameter
+ * - {@link SoundTrigger#STATUS_INVALID_OPERATION} if the call is out of sequence or
+ * if API is not supported by HAL
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
+ public int setParameter(@Nullable UUID soundModelId,
+ @ModelParams int modelParam, int value)
+ throws UnsupportedOperationException, IllegalArgumentException {
+ try {
+ return mSoundTriggerService.setParameter(new ParcelUuid(soundModelId), modelParam,
+ value);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Get a model specific {@link ModelParams}. This parameter will keep its value
+ * for the duration the model is loaded regardless of starting and stopping recognition.
+ * Once the model is unloaded, the value will be lost. If the value is not set, a default
+ * value is returned. See {@link ModelParams} for parameter default values.
+ * {@link SoundTriggerManager#queryParameter} should be checked first before
+ * calling this method. Otherwise, an exception can be thrown.
+ *
+ * @param soundModelId UUID of model to get parameter
+ * @param modelParam {@link ModelParams}
+ * @return value of parameter
+ * @throws UnsupportedOperationException if hal or model do not support this API.
+ * {@link SoundTriggerManager#queryParameter} should be checked first.
+ * @throws IllegalArgumentException if invalid model handle or parameter is passed.
+ * {@link SoundTriggerManager#queryParameter} should be checked first.
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
+ public int getParameter(@NonNull UUID soundModelId,
+ @ModelParams int modelParam)
+ throws UnsupportedOperationException, IllegalArgumentException {
+ try {
+ return mSoundTriggerService.getParameter(new ParcelUuid(soundModelId), modelParam);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Determine if parameter control is supported for the given model handle.
+ * This method should be checked prior to calling {@link SoundTriggerManager#setParameter} or
+ * {@link SoundTriggerManager#getParameter}.
+ *
+ * @param soundModelId handle of model to get parameter
+ * @param modelParam {@link ModelParams}
+ * @return supported range of parameter, null if not supported
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
+ @Nullable
+ public ModelParamRange queryParameter(@Nullable UUID soundModelId,
+ @ModelParams int modelParam) {
+ try {
+ return mSoundTriggerService.queryParameter(new ParcelUuid(soundModelId),
+ modelParam);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/media/java/android/media/tv/ITvInputService.aidl b/media/java/android/media/tv/ITvInputService.aidl
index bd0518493557..f90c50491129 100644..100755
--- a/media/java/android/media/tv/ITvInputService.aidl
+++ b/media/java/android/media/tv/ITvInputService.aidl
@@ -38,4 +38,5 @@ oneway interface ITvInputService {
void notifyHardwareRemoved(in TvInputHardwareInfo hardwareInfo);
void notifyHdmiDeviceAdded(in HdmiDeviceInfo deviceInfo);
void notifyHdmiDeviceRemoved(in HdmiDeviceInfo deviceInfo);
+ void notifyHdmiDeviceUpdated(in HdmiDeviceInfo deviceInfo);
}
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index ff6977914ac3..5c11ed9bb7b4 100644..100755
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -173,6 +173,12 @@ public abstract class TvInputService extends Service {
mServiceHandler.obtainMessage(ServiceHandler.DO_REMOVE_HDMI_INPUT,
deviceInfo).sendToTarget();
}
+
+ @Override
+ public void notifyHdmiDeviceUpdated(HdmiDeviceInfo deviceInfo) {
+ mServiceHandler.obtainMessage(ServiceHandler.DO_UPDATE_HDMI_INPUT,
+ deviceInfo).sendToTarget();
+ }
};
}
@@ -257,6 +263,24 @@ public abstract class TvInputService extends Service {
return null;
}
+ /**
+ * Called when {@code deviceInfo} is updated.
+ *
+ * <p>The changes are usually cuased by the corresponding HDMI-CEC logical device.
+ *
+ * <p>The default behavior ignores all changes.
+ *
+ * <p>The TV input service responsible for {@code deviceInfo} can update the {@link TvInputInfo}
+ * object based on the updated {@code deviceInfo} (e.g. update the label based on the preferred
+ * device OSD name).
+ *
+ * @param deviceInfo the updated {@link HdmiDeviceInfo} object.
+ * @hide
+ */
+ @SystemApi
+ public void onHdmiDeviceUpdated(@NonNull HdmiDeviceInfo deviceInfo) {
+ }
+
private boolean isPassthroughInput(String inputId) {
if (mTvInputManager == null) {
mTvInputManager = (TvInputManager) getSystemService(Context.TV_INPUT_SERVICE);
@@ -1962,6 +1986,7 @@ public abstract class TvInputService extends Service {
private static final int DO_REMOVE_HARDWARE_INPUT = 5;
private static final int DO_ADD_HDMI_INPUT = 6;
private static final int DO_REMOVE_HDMI_INPUT = 7;
+ private static final int DO_UPDATE_HDMI_INPUT = 8;
private void broadcastAddHardwareInput(int deviceId, TvInputInfo inputInfo) {
int n = mCallbacks.beginBroadcast();
@@ -2131,6 +2156,11 @@ public abstract class TvInputService extends Service {
}
return;
}
+ case DO_UPDATE_HDMI_INPUT: {
+ HdmiDeviceInfo deviceInfo = (HdmiDeviceInfo) msg.obj;
+ onHdmiDeviceUpdated(deviceInfo);
+ return;
+ }
default: {
Log.w(TAG, "Unhandled message code: " + msg.what);
return;
diff --git a/media/jni/soundpool/StreamManager.cpp b/media/jni/soundpool/StreamManager.cpp
index c8f0ff10ca3f..79e4d8ae6e26 100644
--- a/media/jni/soundpool/StreamManager.cpp
+++ b/media/jni/soundpool/StreamManager.cpp
@@ -38,7 +38,7 @@ static constexpr bool kStealActiveStream_OldestFirst = true;
// kPlayOnCallingThread = true prior to R.
// Changing to false means calls to play() are almost instantaneous instead of taking around
// ~10ms to launch the AudioTrack. It is perhaps 100x faster.
-static constexpr bool kPlayOnCallingThread = false;
+static constexpr bool kPlayOnCallingThread = true;
// Amount of time for a StreamManager thread to wait before closing.
static constexpr int64_t kWaitTimeBeforeCloseNs = 9 * NANOS_PER_SECOND;
@@ -170,6 +170,7 @@ int32_t StreamManager::queueForPlay(const std::shared_ptr<Sound> &sound,
if (stream->getSoundID() == soundID) {
ALOGV("%s: found soundID %d in restart queue", __func__, soundID);
newStream = stream;
+ fromAvailableQueue = false;
break;
} else if (newStream == nullptr) {
ALOGV("%s: found stream in restart queue", __func__);
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
index bffc6b912146..03bd61ae5e27 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
@@ -35,6 +35,7 @@ import com.android.systemui.stackdivider.Divider;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl;
+import com.android.systemui.statusbar.car.CarShadeControllerImpl;
import com.android.systemui.statusbar.car.CarStatusBar;
import com.android.systemui.statusbar.car.CarStatusBarKeyguardViewManager;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -119,7 +120,7 @@ abstract class CarSystemUIModule {
KeyguardEnvironmentImpl keyguardEnvironment);
@Binds
- abstract ShadeController provideShadeController(CarStatusBar statusBar);
+ abstract ShadeController provideShadeController(CarShadeControllerImpl shadeController);
@Provides
@Singleton
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarShadeControllerImpl.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarShadeControllerImpl.java
new file mode 100644
index 000000000000..d1d352a08908
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarShadeControllerImpl.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.car;
+
+import android.view.View;
+import android.view.WindowManager;
+
+import com.android.car.notification.CarNotificationView;
+import com.android.systemui.assist.AssistManager;
+import com.android.systemui.bubbles.BubbleController;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.phone.ShadeControllerImpl;
+import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.phone.StatusBarWindowController;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import dagger.Lazy;
+
+/** Car specific implementation of {@link com.android.systemui.statusbar.phone.ShadeController}. */
+@Singleton
+public class CarShadeControllerImpl extends ShadeControllerImpl {
+
+ @Inject
+ public CarShadeControllerImpl(CommandQueue commandQueue,
+ StatusBarStateController statusBarStateController,
+ StatusBarWindowController statusBarWindowController,
+ StatusBarKeyguardViewManager statusBarKeyguardViewManager,
+ WindowManager windowManager,
+ Lazy<StatusBar> statusBarLazy,
+ Lazy<AssistManager> assistManagerLazy,
+ Lazy<BubbleController> bubbleControllerLazy) {
+ super(commandQueue, statusBarStateController, statusBarWindowController,
+ statusBarKeyguardViewManager, windowManager,
+ statusBarLazy, assistManagerLazy, bubbleControllerLazy);
+ }
+
+ @Override
+ public void animateCollapsePanels(int flags, boolean force, boolean delayed,
+ float speedUpFactor) {
+ super.animateCollapsePanels(flags, force, delayed, speedUpFactor);
+ if (!getCarStatusBar().isPanelExpanded()
+ || getCarNotificationView().getVisibility() == View.INVISIBLE) {
+ return;
+ }
+
+ mStatusBarWindowController.setStatusBarFocusable(false);
+ getCarStatusBar().getStatusBarWindowViewController().cancelExpandHelper();
+ getStatusBarView().collapsePanel(true /* animate */, delayed, speedUpFactor);
+
+ getCarStatusBar().animateNotificationPanel(getCarStatusBar().getClosingVelocity(), true);
+
+ if (!getCarStatusBar().isTracking()) {
+ mStatusBarWindowController.setPanelVisible(false);
+ getCarNotificationView().setVisibility(View.INVISIBLE);
+ }
+
+ getCarStatusBar().setPanelExpanded(false);
+ }
+
+ private CarStatusBar getCarStatusBar() {
+ return (CarStatusBar) mStatusBarLazy.get();
+ }
+
+ private CarNotificationView getCarNotificationView() {
+ return getCarStatusBar().getCarNotificationView();
+ }
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index c8532e006489..0d6701d76776 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -118,6 +118,7 @@ import com.android.systemui.statusbar.phone.LockscreenWallpaper;
import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.ScrimController;
+import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarComponent;
import com.android.systemui.statusbar.phone.StatusBarIconController;
@@ -175,6 +176,7 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
private final Object mQueueLock = new Object();
private final CarNavigationBarController mCarNavigationBarController;
private final Lazy<PowerManagerHelper> mPowerManagerHelperLazy;
+ private final ShadeController mShadeController;
private final CarServiceProvider mCarServiceProvider;
private DeviceProvisionedController mDeviceProvisionedController;
@@ -308,6 +310,7 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
LightsOutNotifController lightsOutNotifController,
StatusBarNotificationActivityStarter.Builder
statusBarNotificationActivityStarterBuilder,
+ ShadeController shadeController,
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
ViewMediatorCallback viewMediatorCallback,
DismissCallbackRegistry dismissCallbackRegistry,
@@ -385,6 +388,7 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
dividerOptional,
lightsOutNotifController,
statusBarNotificationActivityStarterBuilder,
+ shadeController,
superStatusBarViewFactory,
statusBarKeyguardViewManager,
viewMediatorCallback,
@@ -392,6 +396,7 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
mScrimController = scrimController;
mLockscreenLockIconController = lockscreenLockIconController;
mDeviceProvisionedController = deviceProvisionedController;
+ mShadeController = shadeController;
mCarServiceProvider = carServiceProvider;
mPowerManagerHelperLazy = powerManagerHelperLazy;
mFullscreenUserSwitcherLazy = fullscreenUserSwitcherLazy;
@@ -506,7 +511,7 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
@Override
protected void close() {
if (mPanelExpanded) {
- animateCollapsePanels();
+ mShadeController.animateCollapsePanels();
}
}
});
@@ -516,7 +521,7 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
@Override
protected void close() {
if (mPanelExpanded) {
- animateCollapsePanels();
+ mShadeController.animateCollapsePanels();
}
}
});
@@ -551,7 +556,7 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
mNotificationClickHandlerFactory.registerClickListener((launchResult, alertEntry) -> {
if (launchResult == ActivityManager.START_TASK_TO_FRONT
|| launchResult == ActivityManager.START_SUCCESS) {
- animateCollapsePanels();
+ mShadeController.animateCollapsePanels();
}
});
CarNotificationListener carNotificationListener = new CarNotificationListener();
@@ -712,25 +717,16 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
setPanelExpanded(true);
}
- @Override
- public void animateCollapsePanels(int flags, boolean force, boolean delayed,
- float speedUpFactor) {
- super.animateCollapsePanels(flags, force, delayed, speedUpFactor);
- if (!mPanelExpanded || mNotificationView.getVisibility() == View.INVISIBLE) {
- return;
- }
- mStatusBarWindowController.setStatusBarFocusable(false);
- mStatusBarWindowViewController.cancelExpandHelper();
- mStatusBarView.collapsePanel(true /* animate */, delayed, speedUpFactor);
-
- animateNotificationPanel(mClosingVelocity, true);
+ public CarNotificationView getCarNotificationView() {
+ return mNotificationView;
+ }
- if (!mIsTracking) {
- mStatusBarWindowController.setPanelVisible(false);
- mNotificationView.setVisibility(View.INVISIBLE);
- }
+ public float getClosingVelocity() {
+ return mClosingVelocity;
+ }
- setPanelExpanded(false);
+ public boolean isTracking() {
+ return mIsTracking;
}
private void maybeCompleteAnimation(MotionEvent event) {
@@ -749,7 +745,7 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
* close the notification shade completely with a velocity. If the animation is to close the
* notification shade this method also makes the view invisible after animation ends.
*/
- private void animateNotificationPanel(float velocity, boolean isClosing) {
+ void animateNotificationPanel(float velocity, boolean isClosing) {
float to = 0;
if (!isClosing) {
to = mNotificationView.getHeight();
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
index eff60fa246a4..ff4dc9c7b830 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
@@ -78,6 +78,7 @@ import com.android.systemui.statusbar.phone.LockscreenWallpaper;
import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.ScrimController;
+import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBarComponent;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -183,6 +184,7 @@ public class CarStatusBarModule {
LightsOutNotifController lightsOutNotifController,
StatusBarNotificationActivityStarter.Builder
statusBarNotificationActivityStarterBuilder,
+ ShadeController shadeController,
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
ViewMediatorCallback viewMediatorCallback,
DismissCallbackRegistry dismissCallbackRegistry,
@@ -259,6 +261,7 @@ public class CarStatusBarModule {
superStatusBarViewFactory,
lightsOutNotifController,
statusBarNotificationActivityStarterBuilder,
+ shadeController,
statusBarKeyguardViewManager,
viewMediatorCallback,
dismissCallbackRegistry,
diff --git a/packages/Incremental/NativeAdbDataLoader/Android.bp b/packages/Incremental/NativeAdbDataLoader/Android.bp
new file mode 100644
index 000000000000..5d7b5b6c229d
--- /dev/null
+++ b/packages/Incremental/NativeAdbDataLoader/Android.bp
@@ -0,0 +1,22 @@
+// Copyright 2019, 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.
+
+android_app {
+ name: "NativeAdbDataLoaderService",
+ srcs: ["src/**/*.java"],
+ jni_libs: [ "libnativeadbdataloaderservice_jni"],
+ privileged: true,
+ certificate: "platform",
+ platform_apis: true,
+}
diff --git a/packages/Incremental/NativeAdbDataLoader/AndroidManifest.xml b/packages/Incremental/NativeAdbDataLoader/AndroidManifest.xml
new file mode 100644
index 000000000000..a06dc546f85c
--- /dev/null
+++ b/packages/Incremental/NativeAdbDataLoader/AndroidManifest.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2019, 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.
+*/
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ coreApp="true"
+ package="com.android.incremental.nativeadb"
+ android:sharedUserId="android.uid.system">
+ <uses-permission android:name="android.permission.INTERNET" />
+
+ <application android:label="@string/app_name"
+ android:directBootAware="true">
+
+ <service android:enabled="true"
+ android:name="com.android.incremental.nativeadb.NativeAdbDataLoaderService"
+ android:label="@string/app_name"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.LOAD_DATA" />
+ </intent-filter>
+ </service>
+ </application>
+
+</manifest>
diff --git a/packages/Incremental/NativeAdbDataLoader/jni/Android.bp b/packages/Incremental/NativeAdbDataLoader/jni/Android.bp
new file mode 100644
index 000000000000..0fcfd28cf28c
--- /dev/null
+++ b/packages/Incremental/NativeAdbDataLoader/jni/Android.bp
@@ -0,0 +1,37 @@
+// Copyright 2019, 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.
+
+cc_library_shared {
+ name: "libnativeadbdataloaderservice_jni",
+ cpp_std: "c++2a",
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wunused",
+ "-Wunreachable-code",
+ "-Wno-unused-parameter",
+ ],
+
+ srcs: ["com_android_incremental_nativeadb_DataLoaderService.cpp"],
+
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "libincfs",
+ "libdataloader",
+ "liblog",
+ "libnativehelper",
+ "libutils",
+ ],
+}
diff --git a/packages/Incremental/NativeAdbDataLoader/jni/com_android_incremental_nativeadb_DataLoaderService.cpp b/packages/Incremental/NativeAdbDataLoader/jni/com_android_incremental_nativeadb_DataLoaderService.cpp
new file mode 100644
index 000000000000..de92fcd5b2e8
--- /dev/null
+++ b/packages/Incremental/NativeAdbDataLoader/jni/com_android_incremental_nativeadb_DataLoaderService.cpp
@@ -0,0 +1,519 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_ADB
+#define LOG_TAG "NativeAdbDataLoaderService"
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <android-base/thread_annotations.h>
+#include <android-base/unique_fd.h>
+#include <cutils/trace.h>
+#include <fcntl.h>
+#include <sys/eventfd.h>
+#include <sys/poll.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <utils/Log.h>
+
+#include <charconv>
+#include <string>
+#include <thread>
+#include <type_traits>
+#include <unordered_map>
+#include <unordered_set>
+
+#include "dataloader.h"
+
+#ifndef _WIN32
+#include <endian.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#else
+#define be32toh(x) _byteswap_ulong(x)
+#define be16toh(x) _byteswap_ushort(x)
+#endif
+
+namespace {
+
+using android::base::unique_fd;
+
+using namespace std::literals;
+
+using BlockSize = int16_t;
+using FileId = int16_t;
+using BlockIdx = int32_t;
+using NumBlocks = int32_t;
+using CompressionType = int16_t;
+using RequestType = int16_t;
+
+static constexpr int COMMAND_SIZE = 2 + 2 + 4; // bytes
+static constexpr int HEADER_SIZE = 2 + 2 + 4 + 2; // bytes
+static constexpr std::string_view OKAY = "OKAY"sv;
+
+static constexpr auto PollTimeoutMs = 5000;
+
+static constexpr auto ReadLogBufferSize = 128 * 1024 * 1024;
+static constexpr auto ReadLogMaxEntrySize = 128;
+
+struct BlockHeader {
+ FileId fileId = -1;
+ CompressionType compressionType = -1;
+ BlockIdx blockIdx = -1;
+ BlockSize blockSize = -1;
+} __attribute__((packed));
+
+static_assert(sizeof(BlockHeader) == HEADER_SIZE);
+
+static constexpr RequestType EXIT = 0;
+static constexpr RequestType BLOCK_MISSING = 1;
+static constexpr RequestType PREFETCH = 2;
+
+struct RequestCommand {
+ RequestType requestType;
+ FileId fileId;
+ BlockIdx blockIdx;
+} __attribute__((packed));
+
+static_assert(COMMAND_SIZE == sizeof(RequestCommand));
+
+static bool sendRequest(int fd,
+ RequestType requestType,
+ FileId fileId = -1,
+ BlockIdx blockIdx = -1) {
+ const RequestCommand command{
+ .requestType = static_cast<int16_t>(be16toh(requestType)),
+ .fileId = static_cast<int16_t>(be16toh(fileId)),
+ .blockIdx = static_cast<int32_t>(be32toh(blockIdx))};
+ return android::base::WriteFully(fd, &command, sizeof(command));
+}
+
+static int waitForDataOrSignal(int fd, int event_fd) {
+ struct pollfd pfds[2] = {{fd, POLLIN, 0}, {event_fd, POLLIN, 0}};
+ // Wait indefinitely until either data is ready or stop signal is received
+ int res = poll(pfds, 2, PollTimeoutMs);
+ if (res <= 0) {
+ return res;
+ }
+ // First check if there is a stop signal
+ if (pfds[1].revents == POLLIN) {
+ return event_fd;
+ }
+ // Otherwise check if incoming data is ready
+ if (pfds[0].revents == POLLIN) {
+ return fd;
+ }
+ return -1;
+}
+
+static bool readChunk(int fd, std::vector<uint8_t>& data) {
+ int32_t size;
+ if (!android::base::ReadFully(fd, &size, sizeof(size))) {
+ return false;
+ }
+ size = int32_t(be32toh(size));
+ if (size <= 0) {
+ return false;
+ }
+ data.resize(size);
+ return android::base::ReadFully(fd, data.data(), data.size());
+}
+
+static BlockHeader readHeader(std::span<uint8_t>& data) {
+ BlockHeader header;
+ if (data.size() < sizeof(header)) {
+ return header;
+ }
+
+ header.fileId = static_cast<FileId>(
+ be16toh(*reinterpret_cast<uint16_t*>(&data[0])));
+ header.compressionType = static_cast<CompressionType>(
+ be16toh(*reinterpret_cast<uint16_t*>(&data[2])));
+ header.blockIdx = static_cast<BlockIdx>(
+ be32toh(*reinterpret_cast<uint32_t*>(&data[4])));
+ header.blockSize = static_cast<BlockSize>(
+ be16toh(*reinterpret_cast<uint16_t*>(&data[8])));
+ data = data.subspan(sizeof(header));
+
+ return header;
+}
+
+static std::string extractPackageName(const std::string& staticArgs) {
+ static constexpr auto kPrefix = "package="sv;
+ static constexpr auto kSuffix = "&"sv;
+
+ const auto startPos = staticArgs.find(kPrefix);
+ if (startPos == staticArgs.npos || startPos + kPrefix.size() >= staticArgs.size()) {
+ return {};
+ }
+ const auto endPos = staticArgs.find(kSuffix, startPos + kPrefix.size());
+ return staticArgs.substr(startPos + kPrefix.size(),
+ endPos == staticArgs.npos ? staticArgs.npos
+ : (endPos - (startPos + kPrefix.size())));
+}
+
+class AdbDataLoader : public android::dataloader::DataLoader {
+private:
+ // Lifecycle.
+ bool onCreate(const android::dataloader::DataLoaderParams& params,
+ android::dataloader::FilesystemConnectorPtr ifs,
+ android::dataloader::StatusListenerPtr statusListener,
+ android::dataloader::ServiceConnectorPtr,
+ android::dataloader::ServiceParamsPtr) final {
+ CHECK(ifs) << "ifs can't be null";
+ CHECK(statusListener) << "statusListener can't be null";
+ ALOGE("[AdbDataLoader] onCreate: %s/%s/%d", params.staticArgs().c_str(),
+ params.packageName().c_str(), (int)params.dynamicArgs().size());
+
+ if (params.dynamicArgs().empty()) {
+ ALOGE("[AdbDataLoader] Invalid DataLoaderParams. Need in/out FDs.");
+ return false;
+ }
+ for (auto const& namedFd : params.dynamicArgs()) {
+ if (namedFd.name == "inFd") {
+ mInFd.reset(dup(namedFd.fd));
+ }
+ if (namedFd.name == "outFd") {
+ mOutFd.reset(dup(namedFd.fd));
+ }
+ }
+ if (mInFd < 0 || mOutFd < 0) {
+ ALOGE("[AdbDataLoader] Failed to dup FDs.");
+ return false;
+ }
+
+ mEventFd.reset(eventfd(0, EFD_CLOEXEC));
+ if (mEventFd < 0) {
+ ALOGE("[AdbDataLoader] Failed to create eventfd.");
+ return false;
+ }
+
+ std::string logFile;
+ if (const auto packageName = extractPackageName(params.staticArgs()); !packageName.empty()) {
+ logFile = android::base::GetProperty("adb.readlog." + packageName, "");
+ }
+ if (logFile.empty()) {
+ logFile = android::base::GetProperty("adb.readlog", "");
+ }
+ if (!logFile.empty()) {
+ int flags = O_WRONLY | O_CREAT | O_CLOEXEC;
+ mReadLogFd.reset(
+ TEMP_FAILURE_RETRY(open(logFile.c_str(), flags, 0666)));
+ }
+
+ mIfs = ifs;
+ mStatusListener = statusListener;
+ ALOGE("[AdbDataLoader] Successfully created data loader.");
+ return true;
+ }
+
+ bool onStart() final {
+ char okay_buf[OKAY.size()];
+ if (!android::base::ReadFully(mInFd, okay_buf, OKAY.size())) {
+ ALOGE("[AdbDataLoader] Failed to receive OKAY. Abort.");
+ return false;
+ }
+ if (std::string_view(okay_buf, OKAY.size()) != OKAY) {
+ ALOGE("[AdbDataLoader] Received '%.*s', expecting '%.*s'",
+ (int)OKAY.size(), okay_buf, (int)OKAY.size(), OKAY.data());
+ return false;
+ }
+
+ mReceiverThread = std::thread([this]() { receiver(); });
+ ALOGI("[AdbDataLoader] started loading...");
+ return true;
+ }
+
+ void onStop() final {
+ mStopReceiving = true;
+ eventfd_write(mEventFd, 1);
+ if (mReceiverThread.joinable()) {
+ mReceiverThread.join();
+ }
+ }
+
+ void onDestroy() final {
+ ALOGE("[AdbDataLoader] Sending EXIT to server.");
+ sendRequest(mOutFd, EXIT);
+ // Make sure the receiver thread was stopped
+ CHECK(!mReceiverThread.joinable());
+
+ mInFd.reset();
+ mOutFd.reset();
+
+ mNodeToMetaMap.clear();
+ mIdToNodeMap.clear();
+
+ flushReadLog();
+ mReadLogFd.reset();
+ }
+
+ // IFS callbacks.
+ void onPendingReads(const android::dataloader::PendingReads& pendingReads) final {
+ std::lock_guard lock{mMapsMutex};
+ CHECK(mIfs);
+ for (auto&& pendingRead : pendingReads) {
+ const android::dataloader::Inode ino = pendingRead.file_ino;
+ const auto blockIdx =
+ static_cast<BlockIdx>(pendingRead.block_index);
+ /*
+ ALOGI("[AdbDataLoader] Missing: %d", (int) blockIdx);
+ */
+ auto fileIdOr = getFileId(ino);
+ if (!fileIdOr) {
+ ALOGE("[AdbDataLoader] Failed to handle event for inode=%d. "
+ "Ignore.",
+ static_cast<int>(ino));
+ continue;
+ }
+ const FileId fileId = *fileIdOr;
+ if (mRequestedFiles.insert(fileId).second) {
+ if (!sendRequest(mOutFd, PREFETCH, fileId, blockIdx)) {
+ ALOGE("[AdbDataLoader] Failed to request prefetch for "
+ "inode=%d. Ignore.",
+ static_cast<int>(ino));
+ mRequestedFiles.erase(fileId);
+ mStatusListener->reportStatus(
+ INCREMENTAL_DATA_LOADER_NO_CONNECTION);
+ }
+ }
+ sendRequest(mOutFd, BLOCK_MISSING, fileId, blockIdx);
+ }
+ }
+
+ struct TracedRead {
+ uint64_t timestampUs;
+ uint64_t fileIno;
+ uint32_t firstBlockIdx;
+ uint32_t count;
+ };
+ void onPageReads(const android::dataloader::PageReads& pageReads) final {
+ auto trace = atrace_is_tag_enabled(ATRACE_TAG);
+ auto log = mReadLogFd != -1;
+ if (CC_LIKELY(!(trace || log))) {
+ return;
+ }
+
+ TracedRead last = {0, 0, 0, 0};
+ std::lock_guard lock{mMapsMutex};
+ for (auto&& read : pageReads) {
+ if (read.file_ino != last.fileIno ||
+ read.block_index != last.firstBlockIdx + last.count) {
+ traceOrLogRead(last, trace, log);
+ last = {read.timestamp_us, read.file_ino, read.block_index, 1};
+ } else {
+ ++last.count;
+ }
+ }
+ traceOrLogRead(last, trace, log);
+ }
+ void onFileCreated(android::dataloader::Inode inode, const android::dataloader::RawMetadata& metadata) {
+ }
+
+private:
+ void receiver() {
+ std::vector<uint8_t> data;
+ std::vector<incfs_new_data_block> instructions;
+ while (!mStopReceiving) {
+ const int res = waitForDataOrSignal(mInFd, mEventFd);
+ if (res == 0) {
+ flushReadLog();
+ continue;
+ }
+ if (res < 0) {
+ ALOGE("[AdbDataLoader] failed to poll. Abort.");
+ mStatusListener->reportStatus(INCREMENTAL_DATA_LOADER_NO_CONNECTION);
+ break;
+ }
+ if (res == mEventFd) {
+ ALOGE("[AdbDataLoader] received stop signal. Exit.");
+ break;
+ }
+ if (!readChunk(mInFd, data)) {
+ ALOGE("[AdbDataLoader] failed to read a message. Abort.");
+ mStatusListener->reportStatus(INCREMENTAL_DATA_LOADER_NO_CONNECTION);
+ break;
+ }
+ auto remainingData = std::span(data);
+ while (!remainingData.empty()) {
+ auto header = readHeader(remainingData);
+ if (header.fileId == -1 && header.compressionType == 0 &&
+ header.blockIdx == 0 && header.blockSize == 0) {
+ ALOGI("[AdbDataLoader] stop signal received. Sending "
+ "exit command (remaining bytes: %d).",
+ int(remainingData.size()));
+
+ sendRequest(mOutFd, EXIT);
+ mStopReceiving = true;
+ break;
+ }
+ if (header.fileId < 0 || header.blockSize <= 0 ||
+ header.compressionType < 0 || header.blockIdx < 0) {
+ ALOGE("[AdbDataLoader] invalid header received. Abort.");
+ mStopReceiving = true;
+ break;
+ }
+ const android::dataloader::Inode ino = mIdToNodeMap[header.fileId];
+ if (!ino) {
+ ALOGE("Unknown data destination for file ID %d. "
+ "Ignore.",
+ header.fileId);
+ continue;
+ }
+ auto inst = incfs_new_data_block{
+ .file_ino = static_cast<__aligned_u64>(ino),
+ .block_index = static_cast<uint32_t>(header.blockIdx),
+ .data_len = static_cast<uint16_t>(header.blockSize),
+ .data = reinterpret_cast<uint64_t>(
+ remainingData.data()),
+ .compression =
+ static_cast<uint8_t>(header.compressionType)};
+ instructions.push_back(inst);
+ remainingData = remainingData.subspan(header.blockSize);
+ }
+ writeInstructions(instructions);
+ }
+ writeInstructions(instructions);
+ flushReadLog();
+ }
+
+ void writeInstructions(std::vector<incfs_new_data_block>& instructions) {
+ auto res = this->mIfs->writeBlocks(instructions.data(),
+ instructions.size());
+ if (res != instructions.size()) {
+ ALOGE("[AdbDataLoader] failed to write data to Incfs (res=%d when "
+ "expecting %d)",
+ res, int(instructions.size()));
+ }
+ instructions.clear();
+ }
+
+ struct MetaPair {
+ android::dataloader::RawMetadata meta;
+ FileId fileId;
+ };
+
+ MetaPair* updateMapsForFile(android::dataloader::Inode ino) {
+ android::dataloader::RawMetadata meta = mIfs->getRawMetadata(ino);
+ FileId fileId;
+ auto res =
+ std::from_chars(meta.data(), meta.data() + meta.size(), fileId);
+ if (res.ec != std::errc{} || fileId < 0) {
+ ALOGE("[AdbDataLoader] Invalid metadata for inode=%d (%s)",
+ static_cast<int>(ino), meta.data());
+ return nullptr;
+ }
+ mIdToNodeMap[fileId] = ino;
+ auto& metaPair = mNodeToMetaMap[ino];
+ metaPair.meta = std::move(meta);
+ metaPair.fileId = fileId;
+ return &metaPair;
+ }
+
+ android::dataloader::RawMetadata* getMeta(android::dataloader::Inode ino) {
+ auto it = mNodeToMetaMap.find(ino);
+ if (it != mNodeToMetaMap.end()) {
+ return &it->second.meta;
+ }
+
+ auto metaPair = updateMapsForFile(ino);
+ if (!metaPair) {
+ return nullptr;
+ }
+
+ return &metaPair->meta;
+ }
+
+ FileId* getFileId(android::dataloader::Inode ino) {
+ auto it = mNodeToMetaMap.find(ino);
+ if (it != mNodeToMetaMap.end()) {
+ return &it->second.fileId;
+ }
+
+ auto* metaPair = updateMapsForFile(ino);
+ if (!metaPair) {
+ return nullptr;
+ }
+
+ return &metaPair->fileId;
+ }
+
+ void traceOrLogRead(const TracedRead& read, bool trace, bool log) {
+ if (!read.count) {
+ return;
+ }
+ if (trace) {
+ auto* meta = getMeta(read.fileIno);
+ auto str = android::base::StringPrintf(
+ "page_read: index=%lld count=%lld meta=%.*s",
+ static_cast<long long>(read.firstBlockIdx),
+ static_cast<long long>(read.count),
+ meta ? int(meta->size()) : 0, meta ? meta->data() : "");
+ ATRACE_BEGIN(str.c_str());
+ ATRACE_END();
+ }
+ if (log) {
+ mReadLog.reserve(ReadLogBufferSize);
+
+ auto fileId = getFileId(read.fileIno);
+ android::base::StringAppendF(
+ &mReadLog, "%lld:%lld:%lld:%lld\n",
+ static_cast<long long>(read.timestampUs),
+ static_cast<long long>(fileId ? *fileId : -1),
+ static_cast<long long>(read.firstBlockIdx),
+ static_cast<long long>(read.count));
+
+ if (mReadLog.size() >= mReadLog.capacity() - ReadLogMaxEntrySize) {
+ flushReadLog();
+ }
+ }
+ }
+
+ void flushReadLog() {
+ if (mReadLog.empty() || mReadLogFd == -1) {
+ return;
+ }
+
+ android::base::WriteStringToFd(mReadLog, mReadLogFd);
+ mReadLog.clear();
+ }
+
+private:
+ android::dataloader::FilesystemConnectorPtr mIfs = nullptr;
+ android::dataloader::StatusListenerPtr mStatusListener = nullptr;
+ android::base::unique_fd mInFd;
+ android::base::unique_fd mOutFd;
+ android::base::unique_fd mEventFd;
+ android::base::unique_fd mReadLogFd;
+ std::string mReadLog;
+ std::thread mReceiverThread;
+ std::mutex mMapsMutex;
+ std::unordered_map<android::dataloader::Inode, MetaPair> mNodeToMetaMap GUARDED_BY(mMapsMutex);
+ std::unordered_map<FileId, android::dataloader::Inode> mIdToNodeMap GUARDED_BY(mMapsMutex);
+ /** Tracks which files have been requested */
+ std::unordered_set<FileId> mRequestedFiles;
+ std::atomic<bool> mStopReceiving = false;
+};
+
+} // namespace
+
+int JNI_OnLoad(JavaVM* jvm, void* /* reserved */) {
+ android::dataloader::DataLoader::initialize(
+ [](auto) { return std::make_unique<AdbDataLoader>(); });
+ return JNI_VERSION_1_6;
+}
diff --git a/packages/Incremental/NativeAdbDataLoader/res/values/strings.xml b/packages/Incremental/NativeAdbDataLoader/res/values/strings.xml
new file mode 100644
index 000000000000..9921ae69a7f5
--- /dev/null
+++ b/packages/Incremental/NativeAdbDataLoader/res/values/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Name of the Data Loader Service. [CHAR LIMIT=40] -->
+ <string name="app_name">Native Adb Data Loader Service</string>
+</resources>
diff --git a/packages/Incremental/NativeAdbDataLoader/src/com/android/incremental/nativeadb/NativeAdbDataLoaderService.java b/packages/Incremental/NativeAdbDataLoader/src/com/android/incremental/nativeadb/NativeAdbDataLoaderService.java
new file mode 100644
index 000000000000..1f88114becd8
--- /dev/null
+++ b/packages/Incremental/NativeAdbDataLoader/src/com/android/incremental/nativeadb/NativeAdbDataLoaderService.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2019 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.incremental.nativeadb;
+
+import android.service.incremental.IncrementalDataLoaderService;
+
+/** This code is used for testing only. */
+public class NativeAdbDataLoaderService extends IncrementalDataLoaderService {
+ public static final String TAG = "NativeAdbDataLoaderService";
+ static {
+ System.loadLibrary("nativeadbdataloaderservice_jni");
+ }
+
+ @Override
+ public DataLoader onCreateDataLoader() {
+ return null;
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
index e660e43a60da..d3f9cd4f9034 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
@@ -116,7 +116,7 @@ public class BluetoothUtils {
}
return new Pair<>(
getBluetoothDrawable(context,
- com.android.internal.R.drawable.ic_settings_bluetooth),
+ com.android.internal.R.drawable.ic_settings_bluetooth).mutate(),
context.getString(R.string.bluetooth_talkback_bluetooth));
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 066659677add..747ceb190a5d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -721,12 +721,8 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
refresh();
- if (bondState == BluetoothDevice.BOND_BONDED) {
- if (mDevice.isBluetoothDock()) {
- onBondingDockConnect();
- } else if (mDevice.isBondingInitiatedLocally()) {
- connect(false);
- }
+ if (bondState == BluetoothDevice.BOND_BONDED && mDevice.isBondingInitiatedLocally()) {
+ connect(false);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/OWNERS b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OWNERS
index 7162121330ef..387bae130374 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/OWNERS
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OWNERS
@@ -1,8 +1,7 @@
# Default reviewers for this and subdirectories.
-asapperstein@google.com
-asargent@google.com
-eisenbach@google.com
-jackqdyulei@google.com
siyuanh@google.com
+hughchen@google.com
+timhypeng@google.com
+robertluo@google.com
-# Emergency approvers in case the above are not available \ No newline at end of file
+# Emergency approvers in case the above are not available
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 49e214beaa1e..443543b89a66 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -1395,7 +1395,7 @@ public class AccessPoint implements Comparable<AccessPoint> {
mConfig = new WifiConfiguration();
mConfig.SSID = AccessPoint.convertToQuotedString(ssid);
- if (security == SECURITY_NONE || !getWifiManager().isEasyConnectSupported()) {
+ if (security == SECURITY_NONE) {
mConfig.allowedKeyManagement.set(KeyMgmt.NONE);
} else {
mConfig.allowedKeyManagement.set(KeyMgmt.OWE);
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
index 2a7050651c6d..3818057e8535 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
@@ -1713,4 +1713,21 @@ public class AccessPointTest {
.setScanResults(new ArrayList<ScanResult>(Arrays.asList(scanResult)))
.build();
}
+
+ @Test
+ public void testGenerateOpenNetworkConfig_oweNotSupported_shouldGetCorrectSecurity() {
+ when(mMockContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mMockWifiManager);
+ AccessPoint oweAccessPoint = new TestAccessPointBuilder(mMockContext)
+ .setSecurity(AccessPoint.SECURITY_OWE).build();
+ AccessPoint noneAccessPoint = new TestAccessPointBuilder(mMockContext)
+ .setSecurity(AccessPoint.SECURITY_NONE).build();
+
+ oweAccessPoint.generateOpenNetworkConfig();
+ noneAccessPoint.generateOpenNetworkConfig();
+
+ assertThat(oweAccessPoint.getConfig().allowedKeyManagement.get(KeyMgmt.NONE)).isFalse();
+ assertThat(oweAccessPoint.getConfig().allowedKeyManagement.get(KeyMgmt.OWE)).isTrue();
+ assertThat(noneAccessPoint.getConfig().allowedKeyManagement.get(KeyMgmt.NONE)).isTrue();
+ assertThat(noneAccessPoint.getConfig().allowedKeyManagement.get(KeyMgmt.OWE)).isFalse();
+ }
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 443288cfe492..c19a340498e7 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -28,7 +28,7 @@ import android.database.Cursor;
import android.net.NetworkPolicy;
import android.net.NetworkPolicyManager;
import android.net.Uri;
-import android.net.wifi.WifiConfiguration;
+import android.net.wifi.SoftApConfiguration;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.ParcelFileDescriptor;
@@ -875,32 +875,23 @@ public class SettingsBackupAgent extends BackupAgentHelper {
}
private byte[] getSoftAPConfiguration() {
- try {
- return mWifiManager.getWifiApConfiguration().getBytesForBackup();
- } catch (IOException ioe) {
- Log.e(TAG, "Failed to marshal SoftAPConfiguration" + ioe.getMessage());
- return new byte[0];
- }
+ return mWifiManager.retrieveSoftApBackupData();
}
private void restoreSoftApConfiguration(byte[] data) {
- try {
- WifiConfiguration config = WifiConfiguration
- .getWifiConfigFromBackup(new DataInputStream(new ByteArrayInputStream(data)));
- if (DEBUG) Log.d(TAG, "Successfully unMarshaled WifiConfiguration ");
- int originalApBand = config.apBand;
- mWifiManager.setWifiApConfiguration(config);
+ SoftApConfiguration config = mWifiManager.restoreSoftApBackupData(data);
+ if (config != null) {
+ int originalApBand = config.getBand();
+ if (DEBUG) Log.d(TAG, "Successfully unMarshaled SoftApConfiguration ");
// Depending on device hardware, we may need to notify the user of a setting change for
// the apBand preference
boolean dualMode = mWifiManager.isDualModeSupported();
- int storedApBand = mWifiManager.getWifiApConfiguration().apBand;
+ int storedApBand = mWifiManager.getSoftApConfiguration().getBand();
if (dualMode && storedApBand != originalApBand) {
Log.d(TAG, "restored ap configuration requires a conversion, notify the user");
WifiSoftApBandChangedNotifier.notifyUserOfApBandConversion(this);
}
- } catch (IOException | BackupUtils.BadVersionException e) {
- Log.e(TAG, "Failed to unMarshal SoftAPConfiguration " + e.getMessage());
}
}
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 2a5bdc75361d..404e791291d8 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -127,7 +127,7 @@ android_library {
"SystemUI-proto",
"metrics-helper-lib",
"androidx.test.rules", "hamcrest-library",
- "mockito-target-inline-minus-junit4",
+ "mockito-target-extended-minus-junit4",
"testables",
"truth-prebuilt",
"dagger2-2.19",
diff --git a/packages/SystemUI/plugin_core/Android.bp b/packages/SystemUI/plugin_core/Android.bp
index 42d67620b81d..581fef721acc 100644
--- a/packages/SystemUI/plugin_core/Android.bp
+++ b/packages/SystemUI/plugin_core/Android.bp
@@ -16,4 +16,8 @@ java_library {
sdk_version: "current",
name: "PluginCoreLib",
srcs: ["src/**/*.java"],
+
+ // Enforce that the library is built against java 8 so that there are
+ // no compatibility issues with launcher
+ java_version: "1.8",
}
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 2afcb12da730..d68fe15844c1 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -42,6 +42,7 @@ import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
+import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
@@ -288,6 +289,7 @@ public class BatteryMeterView extends LinearLayout implements
public void onTuningChanged(String key, String newValue) {
if (StatusBarIconController.ICON_BLACKLIST.equals(key)) {
ArraySet<String> icons = StatusBarIconController.getIconBlacklist(newValue);
+ setVisibility(icons.contains(mSlotBattery) ? View.GONE : View.VISIBLE);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 6821265df28b..dd38a332df68 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -124,6 +124,7 @@ import com.android.systemui.util.leak.LeakDetector;
import com.android.systemui.util.leak.LeakReporter;
import com.android.systemui.util.sensors.AsyncSensorManager;
import com.android.systemui.wm.DisplayWindowController;
+import com.android.systemui.wm.SystemWindows;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -323,6 +324,7 @@ public class Dependency {
@Inject Lazy<Recents> mRecents;
@Inject Lazy<StatusBar> mStatusBar;
@Inject Lazy<DisplayWindowController> mDisplayWindowController;
+ @Inject Lazy<SystemWindows> mSystemWindows;
@Inject
public Dependency() {
@@ -513,6 +515,7 @@ public class Dependency {
mProviders.put(Recents.class, mRecents::get);
mProviders.put(StatusBar.class, mStatusBar::get);
mProviders.put(DisplayWindowController.class, mDisplayWindowController::get);
+ mProviders.put(SystemWindows.class, mSystemWindows::get);
// TODO(b/118592525): to support multi-display , we start to add something which is
// per-display, while others may be global. I think it's time to add
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index b5622432f919..db5ff3f1e7ec 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -109,8 +109,6 @@ import java.util.function.Consumer;
import javax.inject.Inject;
import javax.inject.Singleton;
-import dagger.Lazy;
-
/**
* Bubbles are a special type of content that can "float" on top of other apps or System UI.
* Bubbles can be expanded to show more content.
@@ -147,7 +145,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
private BubbleExpandListener mExpandListener;
@Nullable private BubbleStackView.SurfaceSynchronizer mSurfaceSynchronizer;
private final NotificationGroupManager mNotificationGroupManager;
- private final Lazy<ShadeController> mShadeController;
+ private final ShadeController mShadeController;
private final RemoteInputUriController mRemoteInputUriController;
private Handler mHandler = new Handler() {};
@@ -162,6 +160,10 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
// Saves notification keys of user created "fake" bubbles so that we can allow notifications
// like these to bubble by default. Doesn't persist across reboots, not a long-term solution.
private final HashSet<String> mUserCreatedBubbles;
+ // If we're auto-bubbling bubbles via a whitelist, we need to track which notifs from that app
+ // have been "demoted" back to a notification so that we don't auto-bubbles those again.
+ // Doesn't persist across reboots, not a long-term solution.
+ private final HashSet<String> mUserBlockedBubbles;
// Bubbles get added to the status bar view
private final StatusBarWindowController mStatusBarWindowController;
@@ -243,7 +245,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
public BubbleController(Context context,
StatusBarWindowController statusBarWindowController,
StatusBarStateController statusBarStateController,
- Lazy<ShadeController> shadeController,
+ ShadeController shadeController,
BubbleData data,
ConfigurationController configurationController,
NotificationInterruptionStateProvider interruptionStateProvider,
@@ -261,7 +263,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
public BubbleController(Context context,
StatusBarWindowController statusBarWindowController,
StatusBarStateController statusBarStateController,
- Lazy<ShadeController> shadeController,
+ ShadeController shadeController,
BubbleData data,
@Nullable BubbleStackView.SurfaceSynchronizer synchronizer,
ConfigurationController configurationController,
@@ -272,6 +274,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
NotificationEntryManager entryManager,
RemoteInputUriController remoteInputUriController) {
mContext = context;
+ mShadeController = shadeController;
mNotificationInterruptionStateProvider = interruptionStateProvider;
mNotifUserManager = notifUserManager;
mZenModeController = zenModeController;
@@ -319,7 +322,6 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
}
});
- mShadeController = shadeController;
mStatusBarWindowController = statusBarWindowController;
mStatusBarStateListener = new StatusBarStateListener();
statusBarStateController.addCallback(mStatusBarStateListener);
@@ -348,6 +350,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
});
mUserCreatedBubbles = new HashSet<>();
+ mUserBlockedBubbles = new HashSet<>();
mScreenshotHelper = new ScreenshotHelper(context);
}
@@ -579,10 +582,11 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
if (DEBUG_EXPERIMENTS || DEBUG_BUBBLE_CONTROLLER) {
Log.d(TAG, "onUserCreatedBubble: " + entry.getKey());
}
- mShadeController.get().collapsePanel(true);
+ mShadeController.collapsePanel(true);
entry.setFlagBubble(true);
updateBubble(entry, true /* suppressFlyout */, false /* showInShade */);
mUserCreatedBubbles.add(entry.getKey());
+ mUserBlockedBubbles.remove(entry.getKey());
}
/**
@@ -598,6 +602,12 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
entry.setFlagBubble(false);
removeBubble(entry.getKey(), DISMISS_BLOCKED);
mUserCreatedBubbles.remove(entry.getKey());
+ if (BubbleExperimentConfig.isPackageWhitelistedToAutoBubble(
+ mContext, entry.getSbn().getPackageName())) {
+ // This package is whitelist but user demoted the bubble, let's save it so we don't
+ // auto-bubble for the whitelist again.
+ mUserBlockedBubbles.add(entry.getKey());
+ }
}
/**
@@ -727,8 +737,9 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
@Override
public void onPendingEntryAdded(NotificationEntry entry) {
boolean previouslyUserCreated = mUserCreatedBubbles.contains(entry.getKey());
+ boolean userBlocked = mUserBlockedBubbles.contains(entry.getKey());
boolean wasAdjusted = BubbleExperimentConfig.adjustForExperiments(
- mContext, entry, previouslyUserCreated);
+ mContext, entry, previouslyUserCreated, userBlocked);
if (mNotificationInterruptionStateProvider.shouldBubbleUp(entry)
&& (canLaunchInActivityView(mContext, entry) || wasAdjusted)) {
@@ -743,8 +754,9 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
@Override
public void onPreEntryUpdated(NotificationEntry entry) {
boolean previouslyUserCreated = mUserCreatedBubbles.contains(entry.getKey());
+ boolean userBlocked = mUserBlockedBubbles.contains(entry.getKey());
boolean wasAdjusted = BubbleExperimentConfig.adjustForExperiments(
- mContext, entry, previouslyUserCreated);
+ mContext, entry, previouslyUserCreated, userBlocked);
boolean shouldBubble = mNotificationInterruptionStateProvider.shouldBubbleUp(entry)
&& (canLaunchInActivityView(mContext, entry) || wasAdjusted);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
index 41879855275f..21471ec8182b 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
@@ -143,7 +143,7 @@ public class BubbleExperimentConfig {
* @return whether an adjustment was made.
*/
static boolean adjustForExperiments(Context context, NotificationEntry entry,
- boolean previouslyUserCreated) {
+ boolean previouslyUserCreated, boolean userBlocked) {
Notification.BubbleMetadata metadata = null;
boolean addedMetadata = false;
boolean whiteListedToAutoBubble =
@@ -205,7 +205,9 @@ public class BubbleExperimentConfig {
}
}
- boolean bubbleForWhitelist = whiteListedToAutoBubble && (addedMetadata || hasMetadata);
+ boolean bubbleForWhitelist = !userBlocked
+ && whiteListedToAutoBubble
+ && (addedMetadata || hasMetadata);
if ((previouslyUserCreated && addedMetadata) || bubbleForWhitelist) {
// Update to a previous bubble (or new autobubble), set its flag now.
if (DEBUG_EXPERIMENTS) {
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
index 4593164869fd..df793109ae18 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
@@ -22,8 +22,6 @@ import com.android.systemui.ForegroundServicesDialog;
import com.android.systemui.keyguard.WorkLockActivity;
import com.android.systemui.settings.BrightnessDialog;
import com.android.systemui.tuner.TunerActivity;
-import com.android.systemui.usb.UsbDebuggingActivity;
-import com.android.systemui.usb.UsbDebuggingSecondaryUserActivity;
import dagger.Binds;
import dagger.Module;
@@ -58,17 +56,4 @@ public abstract class DefaultActivityBinder {
@IntoMap
@ClassKey(BrightnessDialog.class)
public abstract Activity bindBrightnessDialog(BrightnessDialog activity);
-
- /** Inject into UsbDebuggingActivity. */
- @Binds
- @IntoMap
- @ClassKey(UsbDebuggingActivity.class)
- public abstract Activity bindUsbDebuggingActivity(UsbDebuggingActivity activity);
-
- /** Inject into UsbDebuggingSecondaryUserActivity. */
- @Binds
- @IntoMap
- @ClassKey(UsbDebuggingSecondaryUserActivity.class)
- public abstract Activity bindUsbDebuggingSecondaryUserActivity(
- UsbDebuggingSecondaryUserActivity activity);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
index 606605ad0292..6ea3f4ef958c 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
@@ -20,6 +20,7 @@ import static com.android.systemui.Dependency.TIME_TICK_HANDLER_NAME;
import android.app.INotificationManager;
import android.content.Context;
+import android.content.pm.IPackageManager;
import android.hardware.display.AmbientDisplayConfiguration;
import android.hardware.display.NightDisplayListener;
import android.os.Handler;
@@ -150,6 +151,13 @@ public class DependencyProvider {
/** */
@Singleton
@Provides
+ public IPackageManager provideIPackageManager() {
+ return IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
+ }
+
+ /** */
+ @Singleton
+ @Provides
public LayoutInflater providerLayoutInflater(Context context) {
return LayoutInflater.from(context);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
index f44eae76ec50..ccb6c2f6381e 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
@@ -39,7 +39,7 @@ import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.KeyguardEnvironmentImpl;
import com.android.systemui.statusbar.phone.ShadeController;
-import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.statusbar.phone.ShadeControllerImpl;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import java.util.Optional;
@@ -82,7 +82,7 @@ abstract class SystemUIDefaultModule {
KeyguardEnvironmentImpl keyguardEnvironment);
@Binds
- abstract ShadeController provideShadeController(StatusBar statusBar);
+ abstract ShadeController provideShadeController(ShadeControllerImpl shadeController);
@Singleton
@Provides
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeEvent.java b/packages/SystemUI/src/com/android/systemui/doze/DozeEvent.java
index ea1def07a309..d2fe39424875 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeEvent.java
@@ -28,10 +28,12 @@ import java.lang.annotation.RetentionPolicy;
* and triaging purposes.
*/
public class DozeEvent extends RichEvent {
- public static final int TOTAL_EVENT_TYPES = 19;
-
- public DozeEvent(int logLevel, int type, String reason) {
- super(logLevel, type, reason);
+ /**
+ * Initializes a doze event
+ */
+ public DozeEvent init(@EventType int type, String reason) {
+ super.init(DEBUG, type, reason);
+ return this;
}
/**
@@ -89,21 +91,6 @@ public class DozeEvent extends RichEvent {
}
}
- /**
- * Builds a DozeEvent.
- */
- public static class DozeEventBuilder extends RichEvent.Builder<DozeEventBuilder> {
- @Override
- public DozeEventBuilder getBuilder() {
- return this;
- }
-
- @Override
- public RichEvent build() {
- return new DozeEvent(mLogLevel, mType, mReason);
- }
- }
-
@IntDef({PICKUP_WAKEUP, PULSE_START, PULSE_FINISH, NOTIFICATION_PULSE, DOZING, FLING,
EMERGENCY_CALL, KEYGUARD_BOUNCER_CHANGED, SCREEN_ON, SCREEN_OFF, MISSED_TICK,
TIME_TICK_SCHEDULED, KEYGUARD_VISIBILITY_CHANGE, DOZE_STATE_CHANGED, WAKE_DISPLAY,
@@ -132,6 +119,7 @@ public class DozeEvent extends RichEvent {
public static final int PULSE_DROPPED = 16;
public static final int PULSE_DISABLED_BY_PROX = 17;
public static final int SENSOR_TRIGGERED = 18;
+ public static final int TOTAL_EVENT_TYPES = 19;
public static final int TOTAL_REASONS = 10;
@IntDef({PULSE_REASON_NONE, PULSE_REASON_INTENT, PULSE_REASON_NOTIFICATION,
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
index 2e4466d47927..fe504216b166 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
@@ -35,9 +35,11 @@ import javax.inject.Singleton;
* dependency DumpController DozeLog
*/
@Singleton
-public class DozeLog extends SysuiLog {
+public class DozeLog extends SysuiLog<DozeEvent> {
private static final String TAG = "DozeLog";
+ private DozeEvent mRecycledEvent;
+
private boolean mPulsing;
private long mSince;
private SummaryStats mPickupPulseNearVibrationStats;
@@ -73,8 +75,8 @@ public class DozeLog extends SysuiLog {
* Appends pickup wakeup event to the logs
*/
public void tracePickupWakeUp(boolean withinVibrationThreshold) {
- if (log(DozeEvent.PICKUP_WAKEUP,
- "withinVibrationThreshold=" + withinVibrationThreshold)) {
+ log(DozeEvent.PICKUP_WAKEUP, "withinVibrationThreshold=" + withinVibrationThreshold);
+ if (mEnabled) {
(withinVibrationThreshold ? mPickupPulseNearVibrationStats
: mPickupPulseNotNearVibrationStats).append();
}
@@ -85,27 +87,24 @@ public class DozeLog extends SysuiLog {
* @param reason why the pulse started
*/
public void tracePulseStart(@DozeEvent.Reason int reason) {
- if (log(DozeEvent.PULSE_START, DozeEvent.reasonToString(reason))) {
- mPulsing = true;
- }
+ log(DozeEvent.PULSE_START, DozeEvent.reasonToString(reason));
+ if (mEnabled) mPulsing = true;
}
/**
* Appends pulse finished event to the logs
*/
public void tracePulseFinish() {
- if (log(DozeEvent.PULSE_FINISH)) {
- mPulsing = false;
- }
+ log(DozeEvent.PULSE_FINISH);
+ if (mEnabled) mPulsing = false;
}
/**
* Appends pulse event to the logs
*/
public void traceNotificationPulse() {
- if (log(DozeEvent.NOTIFICATION_PULSE)) {
- mNotificationPulseStats.append();
- }
+ log(DozeEvent.NOTIFICATION_PULSE);
+ if (mEnabled) mNotificationPulseStats.append();
}
/**
@@ -113,9 +112,8 @@ public class DozeLog extends SysuiLog {
* @param dozing true if dozing, else false
*/
public void traceDozing(boolean dozing) {
- if (log(DozeEvent.DOZING, "dozing=" + dozing)) {
- mPulsing = false;
- }
+ log(DozeEvent.DOZING, "dozing=" + dozing);
+ if (mEnabled) mPulsing = false;
}
/**
@@ -133,9 +131,8 @@ public class DozeLog extends SysuiLog {
* Appends emergency call event to the logs
*/
public void traceEmergencyCall() {
- if (log(DozeEvent.EMERGENCY_CALL)) {
- mEmergencyCallStats.append();
- }
+ log(DozeEvent.EMERGENCY_CALL);
+ if (mEnabled) mEmergencyCallStats.append();
}
/**
@@ -150,7 +147,8 @@ public class DozeLog extends SysuiLog {
* Appends screen-on event to the logs
*/
public void traceScreenOn() {
- if (log(DozeEvent.SCREEN_ON, "pulsing=" + mPulsing)) {
+ log(DozeEvent.SCREEN_ON, "pulsing=" + mPulsing);
+ if (mEnabled) {
(mPulsing ? mScreenOnPulsingStats : mScreenOnNotPulsingStats).append();
mPulsing = false;
}
@@ -188,10 +186,8 @@ public class DozeLog extends SysuiLog {
* @param showing whether the keyguard is now showing
*/
public void traceKeyguard(boolean showing) {
- if (log(DozeEvent.KEYGUARD_VISIBILITY_CHANGE, "showing=" + showing)
- && !showing) {
- mPulsing = false;
- }
+ log(DozeEvent.KEYGUARD_VISIBILITY_CHANGE, "showing=" + showing);
+ if (mEnabled && !showing) mPulsing = false;
}
/**
@@ -217,12 +213,11 @@ public class DozeLog extends SysuiLog {
* @param reason why proximity result was triggered
*/
public void traceProximityResult(boolean near, long millis, @DozeEvent.Reason int reason) {
- if (log(DozeEvent.PROXIMITY_RESULT,
+ log(DozeEvent.PROXIMITY_RESULT,
" reason=" + DozeEvent.reasonToString(reason)
- + " near=" + near
- + " millis=" + millis)) {
- mProxStats[reason][near ? 0 : 1].append();
- }
+ + " near=" + near
+ + " millis=" + millis);
+ if (mEnabled) mProxStats[reason][near ? 0 : 1].append();
}
/**
@@ -250,15 +245,16 @@ public class DozeLog extends SysuiLog {
}
}
- private boolean log(@DozeEvent.EventType int eventType) {
- return log(eventType, "");
+ private void log(@DozeEvent.EventType int eventType) {
+ log(eventType, "");
}
- private boolean log(@DozeEvent.EventType int eventType, String msg) {
- return super.log(new DozeEvent.DozeEventBuilder()
- .setType(eventType)
- .setReason(msg)
- .build());
+ private void log(@DozeEvent.EventType int eventType, String msg) {
+ if (mRecycledEvent != null) {
+ mRecycledEvent = log(mRecycledEvent.init(eventType, msg));
+ } else {
+ mRecycledEvent = log(new DozeEvent().init(eventType, msg));
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 8d08b285134c..beba203b9702 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -210,8 +210,7 @@ public class KeyguardViewMediator extends SystemUI {
private AlarmManager mAlarmManager;
private AudioManager mAudioManager;
private StatusBarManager mStatusBarManager;
- private final StatusBarWindowController mStatusBarWindowController =
- Dependency.get(StatusBarWindowController.class);
+ private final StatusBarWindowController mStatusBarWindowController;
private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class);
private boolean mSystemReady;
@@ -688,12 +687,14 @@ public class KeyguardViewMediator extends SystemUI {
FalsingManager falsingManager,
LockPatternUtils lockPatternUtils,
BroadcastDispatcher broadcastDispatcher,
+ StatusBarWindowController statusBarWindowController,
Lazy<StatusBarKeyguardViewManager> statusBarKeyguardViewManagerLazy,
DismissCallbackRegistry dismissCallbackRegistry) {
super(context);
mFalsingManager = falsingManager;
mLockPatternUtils = lockPatternUtils;
mBroadcastDispatcher = broadcastDispatcher;
+ mStatusBarWindowController = statusBarWindowController;
mStatusBarKeyguardViewManagerLazy = statusBarKeyguardViewManagerLazy;
mDismissCallbackRegistry = dismissCallbackRegistry;
}
diff --git a/packages/SystemUI/src/com/android/systemui/log/Event.java b/packages/SystemUI/src/com/android/systemui/log/Event.java
index 92862a2bc74c..7bc1abfbb0d8 100644
--- a/packages/SystemUI/src/com/android/systemui/log/Event.java
+++ b/packages/SystemUI/src/com/android/systemui/log/Event.java
@@ -37,20 +37,28 @@ public class Event {
public static final int INFO = 4;
public static final int WARN = 5;
public static final int ERROR = 6;
+ public static final @Level int DEFAULT_LOG_LEVEL = DEBUG;
private long mTimestamp;
- private @Level int mLogLevel = DEBUG;
- protected String mMessage;
+ private @Level int mLogLevel = DEFAULT_LOG_LEVEL;
+ private String mMessage = "";
- public Event(String message) {
- mTimestamp = System.currentTimeMillis();
- mMessage = message;
+ /**
+ * initialize an event with a message
+ */
+ public Event init(String message) {
+ init(DEFAULT_LOG_LEVEL, message);
+ return this;
}
- public Event(@Level int logLevel, String message) {
+ /**
+ * initialize an event with a logLevel and message
+ */
+ public Event init(@Level int logLevel, String message) {
mTimestamp = System.currentTimeMillis();
mLogLevel = logLevel;
mMessage = message;
+ return this;
}
public String getMessage() {
@@ -64,4 +72,13 @@ public class Event {
public @Level int getLogLevel() {
return mLogLevel;
}
+
+ /**
+ * Recycle this event
+ */
+ void recycle() {
+ mTimestamp = -1;
+ mLogLevel = DEFAULT_LOG_LEVEL;
+ mMessage = "";
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/log/RichEvent.java b/packages/SystemUI/src/com/android/systemui/log/RichEvent.java
index acf761ed3936..470f2b0d1b98 100644
--- a/packages/SystemUI/src/com/android/systemui/log/RichEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/log/RichEvent.java
@@ -23,23 +23,21 @@ package com.android.systemui.log;
* Events are stored in {@link SysuiLog} and can be printed in a dumpsys.
*/
public abstract class RichEvent extends Event {
- private final int mType;
- private final String mReason;
+ private int mType;
/**
- * Create a rich event that includes an event type that matches with an index in the array
+ * Initializes a rich event that includes an event type that matches with an index in the array
* getEventLabels().
*/
- public RichEvent(@Event.Level int logLevel, int type, String reason) {
- super(logLevel, null);
+ public RichEvent init(@Event.Level int logLevel, int type, String reason) {
final int numEvents = getEventLabels().length;
if (type < 0 || type >= numEvents) {
throw new IllegalArgumentException("Unsupported event type. Events only supported"
+ " from 0 to " + (numEvents - 1) + ", but given type=" + type);
}
mType = type;
- mReason = reason;
- mMessage = getEventLabels()[mType] + " " + mReason;
+ super.init(logLevel, getEventLabels()[mType] + " " + reason);
+ return this;
}
/**
@@ -49,25 +47,43 @@ public abstract class RichEvent extends Event {
*/
public abstract String[] getEventLabels();
- public int getType() {
- return mType;
+ @Override
+ public void recycle() {
+ super.recycle();
+ mType = -1;
}
- public String getReason() {
- return mReason;
+ public int getType() {
+ return mType;
}
/**
* Builder to build a RichEvent.
* @param <B> Log specific builder that is extending this builder
+ * @param <E> Type of event we'll be building
*/
- public abstract static class Builder<B extends Builder<B>> {
+ public abstract static class Builder<B extends Builder<B, E>, E extends RichEvent> {
public static final int UNINITIALIZED = -1;
+ public final SysuiLog mLog;
private B mBuilder = getBuilder();
- protected int mType = UNINITIALIZED;
+ protected int mType;
protected String mReason;
- protected @Level int mLogLevel = VERBOSE;
+ protected @Level int mLogLevel;
+
+ public Builder(SysuiLog sysuiLog) {
+ mLog = sysuiLog;
+ reset();
+ }
+
+ /**
+ * Reset this builder's parameters so it can be reused to build another RichEvent.
+ */
+ public void reset() {
+ mType = UNINITIALIZED;
+ mReason = null;
+ mLogLevel = VERBOSE;
+ }
/**
* Get the log-specific builder.
@@ -75,9 +91,9 @@ public abstract class RichEvent extends Event {
public abstract B getBuilder();
/**
- * Build the log-specific event.
+ * Build the log-specific event given an event to populate.
*/
- public abstract RichEvent build();
+ public abstract E build(E e);
/**
* Optional - set the log level. Defaults to DEBUG.
diff --git a/packages/SystemUI/src/com/android/systemui/log/SysuiLog.java b/packages/SystemUI/src/com/android/systemui/log/SysuiLog.java
index 0f71d22b218f..4e15668f6a34 100644
--- a/packages/SystemUI/src/com/android/systemui/log/SysuiLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/SysuiLog.java
@@ -20,6 +20,7 @@ import android.os.Build;
import android.os.SystemProperties;
import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.DumpController;
import com.android.systemui.Dumpable;
@@ -39,23 +40,26 @@ import java.util.Locale;
* To manually view the logs via adb:
* adb shell dumpsys activity service com.android.systemui/.SystemUIService \
* dependency DumpController <SysuiLogId>
+ *
+ * Logs can be disabled by setting the following SystemProperty and then restarting the device:
+ * adb shell setprop persist.sysui.log.enabled.<id> true/false && adb reboot
+ *
+ * @param <E> Type of event we'll be logging
*/
-public class SysuiLog implements Dumpable {
+public class SysuiLog<E extends Event> implements Dumpable {
public static final SimpleDateFormat DATE_FORMAT =
new SimpleDateFormat("MM-dd HH:mm:ss", Locale.US);
- private final Object mDataLock = new Object();
+ protected final Object mDataLock = new Object();
private final String mId;
private final int mMaxLogs;
protected boolean mEnabled;
protected boolean mLogToLogcatEnabled;
- @VisibleForTesting protected ArrayDeque<Event> mTimeline;
+ @VisibleForTesting protected ArrayDeque<E> mTimeline;
/**
* Creates a SysuiLog
- * To enable or disable logs, set the system property and then restart the device:
- * adb shell setprop sysui.log.enabled.<id> true/false && adb reboot
* @param dumpController where to register this logger's dumpsys
* @param id user-readable tag for this logger
* @param maxDebugLogs maximum number of logs to retain when {@link sDebuggable} is true
@@ -79,23 +83,20 @@ public class SysuiLog implements Dumpable {
dumpController.registerDumpable(mId, this);
}
- public SysuiLog(DumpController dumpController, String id) {
- this(dumpController, id, DEFAULT_MAX_DEBUG_LOGS, DEFAULT_MAX_LOGS);
- }
-
/**
* Logs an event to the timeline which can be printed by the dumpsys.
* May also log to logcat if enabled.
- * @return true if event was logged, else false
+ * @return the last event that was discarded from the Timeline (can be recycled)
*/
- public boolean log(Event event) {
+ public E log(E event) {
if (!mEnabled) {
- return false;
+ return null;
}
+ E recycledEvent = null;
synchronized (mDataLock) {
if (mTimeline.size() >= mMaxLogs) {
- mTimeline.removeFirst();
+ recycledEvent = mTimeline.removeFirst();
}
mTimeline.add(event);
@@ -121,13 +122,18 @@ public class SysuiLog implements Dumpable {
break;
}
}
- return true;
+
+ if (recycledEvent != null) {
+ recycledEvent.recycle();
+ }
+
+ return recycledEvent;
}
/**
* @return user-readable string of the given event with timestamp
*/
- public String eventToTimestampedString(Event event) {
+ private String eventToTimestampedString(Event event) {
StringBuilder sb = new StringBuilder();
sb.append(SysuiLog.DATE_FORMAT.format(event.getTimestamp()));
sb.append(" ");
@@ -142,9 +148,7 @@ public class SysuiLog implements Dumpable {
return event.getMessage();
}
- /**
- * only call on this method if you have the mDataLock
- */
+ @GuardedBy("mDataLock")
private void dumpTimelineLocked(PrintWriter pw) {
pw.println("\tTimeline:");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
index 9dcfb6a8a4c6..9a64b30ed918 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
@@ -38,6 +38,7 @@ import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.NotificationListenerWithPlugins;
import java.util.ArrayList;
+import java.util.List;
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -89,11 +90,22 @@ public class NotificationListener extends NotificationListenerWithPlugins {
}
final RankingMap currentRanking = getCurrentRanking();
mMainHandler.post(() -> {
+ // There's currently a race condition between the calls to getActiveNotifications() and
+ // getCurrentRanking(). It's possible for the ranking that we store here to not contain
+ // entries for every notification in getActiveNotifications(). To prevent downstream
+ // crashes, we temporarily fill in these missing rankings with stubs.
+ // See b/146011844 for long-term fix
+ final List<Ranking> newRankings = new ArrayList<>();
+ for (StatusBarNotification sbn : notifications) {
+ newRankings.add(getRankingOrTemporaryStandIn(currentRanking, sbn.getKey()));
+ }
+ final RankingMap completeMap = new RankingMap(newRankings.toArray(new Ranking[0]));
+
for (StatusBarNotification sbn : notifications) {
if (mDownstreamListener != null) {
- mDownstreamListener.onNotificationPosted(sbn, currentRanking);
+ mDownstreamListener.onNotificationPosted(sbn, completeMap);
}
- mEntryManager.addNotification(sbn, currentRanking);
+ mEntryManager.addNotification(sbn, completeMap);
}
});
NotificationManager noMan = mContext.getSystemService(NotificationManager.class);
@@ -192,6 +204,35 @@ public class NotificationListener extends NotificationListenerWithPlugins {
}
}
+ private static Ranking getRankingOrTemporaryStandIn(RankingMap rankingMap, String key) {
+ Ranking ranking = new Ranking();
+ if (!rankingMap.getRanking(key, ranking)) {
+ ranking.populate(
+ key,
+ 0,
+ false,
+ 0,
+ 0,
+ 0,
+ null,
+ null,
+ null,
+ new ArrayList<>(),
+ new ArrayList<>(),
+ false,
+ 0,
+ false,
+ 0,
+ false,
+ new ArrayList<>(),
+ new ArrayList<>(),
+ false,
+ false
+ );
+ }
+ return ranking;
+ }
+
public interface NotificationSettingsListener {
default void onStatusBarIconsBehaviorChanged(boolean hideSilentStatusIcons) { }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationUpdateHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationUpdateHandler.java
deleted file mode 100644
index 1ac81982505e..000000000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationUpdateHandler.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar;
-
-import android.service.notification.NotificationListenerService;
-import android.service.notification.StatusBarNotification;
-
-/**
- * Interface for accepting notification updates from {@link NotificationListener}.
- */
-public interface NotificationUpdateHandler {
- /**
- * Add a new notification and update the current notification ranking map.
- *
- * @param notification Notification to add
- * @param ranking RankingMap to update with
- */
- void addNotification(StatusBarNotification notification,
- NotificationListenerService.RankingMap ranking);
-
- /**
- * Remove a notification and update the current notification ranking map.
- *
- * @param key Key identifying the notification to remove
- * @param ranking RankingMap to update with
- * @param reason why the notification is being removed, e.g.
- * {@link NotificationListenerService#REASON_CANCEL}.
- */
- void removeNotification(String key, NotificationListenerService.RankingMap ranking, int reason);
-
- /**
- * Update a given notification and the current notification ranking map.
- *
- * @param notification Updated notification
- * @param ranking RankingMap to update with
- */
- void updateNotification(StatusBarNotification notification,
- NotificationListenerService.RankingMap ranking);
-
- /**
- * Update with a new notification ranking map.
- *
- * @param ranking RankingMap to update with
- */
- void updateNotificationRanking(NotificationListenerService.RankingMap ranking);
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index 4204f684a632..1648196ec0ea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -37,7 +37,6 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
-import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.util.Assert;
import com.android.systemui.util.Utils;
@@ -49,8 +48,6 @@ import java.util.Stack;
import javax.inject.Inject;
import javax.inject.Singleton;
-import dagger.Lazy;
-
/**
* NotificationViewHierarchyManager manages updating the view hierarchy of notification views based
* on their group structure. For example, if a notification becomes bundled with another,
@@ -75,9 +72,6 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
private final SysuiStatusBarStateController mStatusBarStateController;
private final NotificationEntryManager mEntryManager;
- // Lazy
- private final Lazy<ShadeController> mShadeController;
-
/**
* {@code true} if notifications not part of a group should by default be rendered in their
* expanded state. If {@code false}, then only the first notification will be expanded if
@@ -105,7 +99,6 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
VisualStabilityManager visualStabilityManager,
StatusBarStateController statusBarStateController,
NotificationEntryManager notificationEntryManager,
- Lazy<ShadeController> shadeController,
KeyguardBypassController bypassController,
BubbleController bubbleController,
DynamicPrivacyController privacyController) {
@@ -117,7 +110,6 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
mVisualStabilityManager = visualStabilityManager;
mStatusBarStateController = (SysuiStatusBarStateController) statusBarStateController;
mEntryManager = notificationEntryManager;
- mShadeController = shadeController;
Resources res = context.getResources();
mAlwaysExpandNonGroupedNotification =
res.getBoolean(R.bool.config_alwaysExpandNonGroupedNotifications);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index 7a58097f3ec1..dbefc7b4514e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -37,7 +37,6 @@ import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationRemoveInterceptor;
import com.android.systemui.statusbar.NotificationUiAdjustment;
-import com.android.systemui.statusbar.NotificationUpdateHandler;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
import com.android.systemui.statusbar.notification.collection.NotificationRowBinder;
@@ -94,7 +93,6 @@ import javax.inject.Singleton;
public class NotificationEntryManager implements
Dumpable,
NotificationContentInflater.InflationCallback,
- NotificationUpdateHandler,
VisualStabilityManager.Callback {
private static final String TAG = "NotificationEntryMgr";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -267,14 +265,13 @@ public class NotificationEntryManager implements
NotificationEntry entry = mPendingNotifications.get(key);
entry.abortTask();
mPendingNotifications.remove(key);
- mNotifLog.log(NotifEvent.INFLATION_ABORTED, entry.getSbn(), null,
- "PendingNotification aborted. " + reason);
+ mNotifLog.log(NotifEvent.INFLATION_ABORTED, entry, "PendingNotification aborted"
+ + " reason=" + reason);
}
NotificationEntry addedEntry = getActiveNotificationUnfiltered(key);
if (addedEntry != null) {
addedEntry.abortTask();
- mNotifLog.log(NotifEvent.INFLATION_ABORTED, addedEntry.getSbn(),
- null, reason);
+ mNotifLog.log(NotifEvent.INFLATION_ABORTED, addedEntry.getKey() + " " + reason);
}
}
@@ -347,7 +344,6 @@ public class NotificationEntryManager implements
}
- @Override
public void removeNotification(String key, RankingMap ranking,
int reason) {
removeNotificationInternal(key, ranking, obtainVisibility(key), false /* forceRemove */,
@@ -501,13 +497,12 @@ public class NotificationEntryManager implements
abortExistingInflation(key, "addNotification");
mPendingNotifications.put(key, entry);
- mNotifLog.log(NotifEvent.NOTIF_ADDED, entry.getSbn());
+ mNotifLog.log(NotifEvent.NOTIF_ADDED, entry);
for (NotificationEntryListener listener : mNotificationEntryListeners) {
listener.onPendingEntryAdded(entry);
}
}
- @Override
public void addNotification(StatusBarNotification notification, RankingMap ranking) {
try {
addNotificationInternal(notification, ranking);
@@ -536,7 +531,7 @@ public class NotificationEntryManager implements
entry.setSbn(notification);
mGroupManager.onEntryUpdated(entry, oldSbn);
- mNotifLog.log(NotifEvent.NOTIF_UPDATED, entry.getSbn(), entry.getRanking());
+ mNotifLog.log(NotifEvent.NOTIF_UPDATED, entry);
for (NotificationEntryListener listener : mNotificationEntryListeners) {
listener.onPreEntryUpdated(entry);
}
@@ -557,7 +552,6 @@ public class NotificationEntryManager implements
}
}
- @Override
public void updateNotification(StatusBarNotification notification, RankingMap ranking) {
try {
updateNotificationInternal(notification, ranking);
@@ -577,7 +571,6 @@ public class NotificationEntryManager implements
}
}
- @Override
public void updateNotificationRanking(RankingMap rankingMap) {
List<NotificationEntry> entries = new ArrayList<>();
entries.addAll(getVisibleNotifications());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImpl.java
index 21a4b4f895e5..a1cfb5424c08 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImpl.java
@@ -29,7 +29,6 @@ import static com.android.systemui.statusbar.notification.collection.listbuilder
import android.annotation.MainThread;
import android.annotation.Nullable;
import android.util.ArrayMap;
-import android.util.Log;
import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener;
@@ -40,6 +39,8 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.SectionsProvider;
+import com.android.systemui.statusbar.notification.logging.NotifEvent;
+import com.android.systemui.statusbar.notification.logging.NotifLog;
import com.android.systemui.util.Assert;
import com.android.systemui.util.time.SystemClock;
@@ -59,8 +60,8 @@ import javax.inject.Singleton;
@MainThread
@Singleton
public class NotifListBuilderImpl implements NotifListBuilder {
-
private final SystemClock mSystemClock;
+ private final NotifLog mNotifLog;
private final List<ListEntry> mNotifList = new ArrayList<>();
@@ -86,9 +87,10 @@ public class NotifListBuilderImpl implements NotifListBuilder {
private final List<ListEntry> mReadOnlyNotifList = Collections.unmodifiableList(mNotifList);
@Inject
- public NotifListBuilderImpl(SystemClock systemClock) {
+ public NotifListBuilderImpl(SystemClock systemClock, NotifLog notifLog) {
Assert.isMainThread();
mSystemClock = systemClock;
+ mNotifLog = notifLog;
}
/**
@@ -193,7 +195,8 @@ public class NotifListBuilderImpl implements NotifListBuilder {
Assert.isMainThread();
mPipelineState.requireIsBefore(STATE_BUILD_STARTED);
- Log.i(TAG, "Build request received from NotifCollection");
+ mNotifLog.log(NotifEvent.ON_BUILD_LIST, "Request received from "
+ + "NotifCollection");
mAllEntries = entries;
buildList();
}
@@ -202,8 +205,7 @@ public class NotifListBuilderImpl implements NotifListBuilder {
private void onFilterInvalidated(NotifFilter filter) {
Assert.isMainThread();
- // TODO: Convert these log statements (here and elsewhere) into timeline logging
- Log.i(TAG, String.format(
+ mNotifLog.log(NotifEvent.FILTER_INVALIDATED, String.format(
"Filter \"%s\" invalidated; pipeline state is %d",
filter.getName(),
mPipelineState.getState()));
@@ -214,7 +216,7 @@ public class NotifListBuilderImpl implements NotifListBuilder {
private void onPromoterInvalidated(NotifPromoter filter) {
Assert.isMainThread();
- Log.i(TAG, String.format(
+ mNotifLog.log(NotifEvent.PROMOTER_INVALIDATED, String.format(
"NotifPromoter \"%s\" invalidated; pipeline state is %d",
filter.getName(),
mPipelineState.getState()));
@@ -225,7 +227,7 @@ public class NotifListBuilderImpl implements NotifListBuilder {
private void onSectionsProviderInvalidated(SectionsProvider provider) {
Assert.isMainThread();
- Log.i(TAG, String.format(
+ mNotifLog.log(NotifEvent.SECTIONS_PROVIDER_INVALIDATED, String.format(
"Sections provider \"%s\" invalidated; pipeline state is %d",
provider.getName(),
mPipelineState.getState()));
@@ -236,7 +238,7 @@ public class NotifListBuilderImpl implements NotifListBuilder {
private void onNotifComparatorInvalidated(NotifComparator comparator) {
Assert.isMainThread();
- Log.i(TAG, String.format(
+ mNotifLog.log(NotifEvent.COMPARATOR_INVALIDATED, String.format(
"Comparator \"%s\" invalidated; pipeline state is %d",
comparator.getName(),
mPipelineState.getState()));
@@ -254,7 +256,7 @@ public class NotifListBuilderImpl implements NotifListBuilder {
* if we detect that behavior, we should crash instantly.
*/
private void buildList() {
- Log.i(TAG, "Starting notif list build #" + mIterationCount + "...");
+ mNotifLog.log(NotifEvent.START_BUILD_LIST, "Run #" + mIterationCount + "...");
mPipelineState.requireIsBefore(STATE_BUILD_STARTED);
mPipelineState.setState(STATE_BUILD_STARTED);
@@ -288,15 +290,16 @@ public class NotifListBuilderImpl implements NotifListBuilder {
freeEmptyGroups();
// Step 5: Dispatch the new list, first to any listeners and then to the view layer
- Log.i(TAG, "List finalized, is:\n" + dumpList(mNotifList));
- Log.i(TAG, "Dispatching final list to listeners...");
+ mNotifLog.log(NotifEvent.DISPATCH_FINAL_LIST, "List finalized, is:\n"
+ + dumpList(mNotifList));
dispatchOnBeforeRenderList(mReadOnlyNotifList);
if (mOnRenderListListener != null) {
mOnRenderListListener.onRenderList(mReadOnlyNotifList);
}
// Step 6: We're done!
- Log.i(TAG, "Notif list build #" + mIterationCount + " completed");
+ mNotifLog.log(NotifEvent.LIST_BUILD_COMPLETE,
+ "Notif list build #" + mIterationCount + " completed");
mPipelineState.setState(STATE_IDLE);
mIterationCount++;
}
@@ -354,7 +357,7 @@ public class NotifListBuilderImpl implements NotifListBuilder {
if (existingSummary == null) {
group.setSummary(entry);
} else {
- Log.w(TAG, String.format(
+ mNotifLog.log(NotifEvent.WARN, String.format(
"Duplicate summary for group '%s': '%s' vs. '%s'",
group.getKey(),
existingSummary.getKey(),
@@ -377,7 +380,8 @@ public class NotifListBuilderImpl implements NotifListBuilder {
final String topLevelKey = entry.getKey();
if (mGroups.containsKey(topLevelKey)) {
- Log.wtf(TAG, "Duplicate non-group top-level key: " + topLevelKey);
+ mNotifLog.log(NotifEvent.WARN,
+ "Duplicate non-group top-level key: " + topLevelKey);
} else {
entry.setParent(ROOT_ENTRY);
out.add(entry);
@@ -539,7 +543,7 @@ public class NotifListBuilderImpl implements NotifListBuilder {
private void logParentingChanges() {
for (NotificationEntry entry : mAllEntries) {
if (entry.getParent() != entry.getPreviousParent()) {
- Log.i(TAG, String.format(
+ mNotifLog.log(NotifEvent.PARENT_CHANGED, String.format(
"%s: parent changed from %s to %s",
entry.getKey(),
entry.getPreviousParent() == null
@@ -550,7 +554,7 @@ public class NotifListBuilderImpl implements NotifListBuilder {
}
for (GroupEntry group : mGroups.values()) {
if (group.getParent() != group.getPreviousParent()) {
- Log.i(TAG, String.format(
+ mNotifLog.log(NotifEvent.PARENT_CHANGED, String.format(
"%s: parent changed from %s to %s",
group.getKey(),
group.getPreviousParent() == null
@@ -607,17 +611,17 @@ public class NotifListBuilderImpl implements NotifListBuilder {
if (filter != entry.mExcludingFilter) {
if (entry.mExcludingFilter == null) {
- Log.i(TAG, String.format(
+ mNotifLog.log(NotifEvent.FILTER_CHANGED, String.format(
"%s: filtered out by '%s'",
entry.getKey(),
filter.getName()));
} else if (filter == null) {
- Log.i(TAG, String.format(
+ mNotifLog.log(NotifEvent.FILTER_CHANGED, String.format(
"%s: no longer filtered out (previous filter was '%s')",
entry.getKey(),
entry.mExcludingFilter.getName()));
} else {
- Log.i(TAG, String.format(
+ mNotifLog.log(NotifEvent.FILTER_CHANGED, String.format(
"%s: filter changed: '%s' -> '%s'",
entry.getKey(),
entry.mExcludingFilter,
@@ -648,23 +652,22 @@ public class NotifListBuilderImpl implements NotifListBuilder {
if (promoter != entry.mNotifPromoter) {
if (entry.mNotifPromoter == null) {
- Log.i(TAG, String.format(
+ mNotifLog.log(NotifEvent.PROMOTER_CHANGED, String.format(
"%s: Entry promoted to top level by '%s'",
entry.getKey(),
promoter.getName()));
} else if (promoter == null) {
- Log.i(TAG, String.format(
+ mNotifLog.log(NotifEvent.PROMOTER_CHANGED, String.format(
"%s: Entry is no longer promoted to top level (previous promoter was '%s')",
entry.getKey(),
entry.mNotifPromoter.getName()));
} else {
- Log.i(TAG, String.format(
+ mNotifLog.log(NotifEvent.PROMOTER_CHANGED, String.format(
"%s: Top-level promoter changed: '%s' -> '%s'",
entry.getKey(),
entry.mNotifPromoter,
promoter));
}
-
entry.mNotifPromoter = promoter;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java
index 511aafc2d12a..b68cb0dd3320 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.notification.collection.coordinator;
import android.Manifest;
-import android.app.AppGlobals;
import android.app.Notification;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
@@ -43,10 +42,13 @@ public class DeviceProvisionedCoordinator implements Coordinator {
private static final String TAG = "DeviceProvisionedCoordinator";
private final DeviceProvisionedController mDeviceProvisionedController;
+ private final IPackageManager mIPackageManager;
@Inject
- public DeviceProvisionedCoordinator(DeviceProvisionedController deviceProvisionedController) {
+ public DeviceProvisionedCoordinator(DeviceProvisionedController deviceProvisionedController,
+ IPackageManager packageManager) {
mDeviceProvisionedController = deviceProvisionedController;
+ mIPackageManager = packageManager;
}
@Override
@@ -56,7 +58,7 @@ public class DeviceProvisionedCoordinator implements Coordinator {
notifListBuilder.addFilter(mNotifFilter);
}
- protected final NotifFilter mNotifFilter = new NotifFilter(TAG) {
+ private final NotifFilter mNotifFilter = new NotifFilter(TAG) {
@Override
public boolean shouldFilterOut(NotificationEntry entry, long now) {
return !mDeviceProvisionedController.isDeviceProvisioned()
@@ -70,17 +72,16 @@ public class DeviceProvisionedCoordinator implements Coordinator {
* marking them as relevant for setup are allowed to show when device is unprovisioned
*/
private boolean showNotificationEvenIfUnprovisioned(StatusBarNotification sbn) {
- final boolean hasPermission = checkUidPermission(AppGlobals.getPackageManager(),
+ final boolean hasPermission = checkUidPermission(
Manifest.permission.NOTIFICATION_DURING_SETUP,
sbn.getUid()) == PackageManager.PERMISSION_GRANTED;
return hasPermission
&& sbn.getNotification().extras.getBoolean(Notification.EXTRA_ALLOW_DURING_SETUP);
}
- private static int checkUidPermission(IPackageManager packageManager, String permission,
- int uid) {
+ private int checkUidPermission(String permission, int uid) {
try {
- return packageManager.checkUidPermission(permission, uid);
+ return mIPackageManager.checkUidPermission(permission, uid);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinator.java
index 4803cf478327..378599b79cc0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinator.java
@@ -24,7 +24,6 @@ import android.util.ArraySet;
import com.android.systemui.ForegroundServiceController;
import com.android.systemui.appops.AppOpsController;
-import com.android.systemui.dagger.qualifiers.BgHandler;
import com.android.systemui.dagger.qualifiers.MainHandler;
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifCollectionListener;
@@ -52,12 +51,11 @@ import javax.inject.Singleton;
*/
@Singleton
public class ForegroundCoordinator implements Coordinator {
- private static final String TAG = "ForegroundNotificationCoordinator";
+ private static final String TAG = "ForegroundCoordinator";
private final ForegroundServiceController mForegroundServiceController;
private final AppOpsController mAppOpsController;
private final Handler mMainHandler;
- private final Handler mBgHandler;
private NotifCollection mNotifCollection;
@@ -65,12 +63,10 @@ public class ForegroundCoordinator implements Coordinator {
public ForegroundCoordinator(
ForegroundServiceController foregroundServiceController,
AppOpsController appOpsController,
- @MainHandler Handler mainHandler,
- @BgHandler Handler bgHandler) {
+ @MainHandler Handler mainHandler) {
mForegroundServiceController = foregroundServiceController;
mAppOpsController = appOpsController;
mMainHandler = mainHandler;
- mBgHandler = bgHandler;
}
@Override
@@ -93,7 +89,7 @@ public class ForegroundCoordinator implements Coordinator {
/**
* Filters out notifications that represent foreground services that are no longer running.
*/
- protected final NotifFilter mNotifFilter = new NotifFilter(TAG) {
+ private final NotifFilter mNotifFilter = new NotifFilter(TAG) {
@Override
public boolean shouldFilterOut(NotificationEntry entry, long now) {
StatusBarNotification sbn = entry.getSbn();
@@ -120,7 +116,8 @@ public class ForegroundCoordinator implements Coordinator {
* Extends the lifetime of foreground notification services such that they show for at least
* five seconds
*/
- private final NotifLifetimeExtender mForegroundLifetimeExtender = new NotifLifetimeExtender() {
+ private final NotifLifetimeExtender mForegroundLifetimeExtender =
+ new NotifLifetimeExtender() {
private static final int MIN_FGS_TIME_MS = 5000;
private OnEndLifetimeExtensionCallback mEndCallback;
private Map<String, Runnable> mEndRunnables = new HashMap<>();
@@ -154,8 +151,8 @@ public class ForegroundCoordinator implements Coordinator {
}
};
mEndRunnables.put(entry.getKey(), runnable);
- mBgHandler.postDelayed(runnable, MIN_FGS_TIME_MS
- - (currTime - entry.getSbn().getPostTime()));
+ mMainHandler.postDelayed(runnable,
+ MIN_FGS_TIME_MS - (currTime - entry.getSbn().getPostTime()));
}
}
@@ -166,7 +163,7 @@ public class ForegroundCoordinator implements Coordinator {
public void cancelLifetimeExtension(NotificationEntry entry) {
if (mEndRunnables.containsKey(entry.getKey())) {
Runnable endRunnable = mEndRunnables.remove(entry.getKey());
- mBgHandler.removeCallbacks(endRunnable);
+ mMainHandler.removeCallbacks(endRunnable);
}
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
index 6daf3fc50b30..4413dc46724a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
@@ -51,7 +51,7 @@ import javax.inject.Singleton;
*/
@Singleton
public class KeyguardCoordinator implements Coordinator {
- private static final String TAG = "KeyguardNotificationCoordinator";
+ private static final String TAG = "KeyguardCoordinator";
private final Context mContext;
private final Handler mMainHandler;
@@ -86,7 +86,7 @@ public class KeyguardCoordinator implements Coordinator {
notifListBuilder.addFilter(mNotifFilter);
}
- protected final NotifFilter mNotifFilter = new NotifFilter(TAG) {
+ private final NotifFilter mNotifFilter = new NotifFilter(TAG) {
@Override
public boolean shouldFilterOut(NotificationEntry entry, long now) {
final StatusBarNotification sbn = entry.getSbn();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java
index c390f96f004d..24e7a79e9588 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java
@@ -26,7 +26,10 @@ import javax.inject.Inject;
import javax.inject.Singleton;
/**
- * Filters out NotificationEntries based on its Ranking.
+ * Filters out NotificationEntries based on its Ranking and dozing state.
+ * We check the NotificationEntry's Ranking for:
+ * - whether the notification's app is suspended or hiding its notifications
+ * - whether DND settings are hiding notifications from ambient display or the notification list
*/
@Singleton
public class RankingCoordinator implements Coordinator {
@@ -51,7 +54,7 @@ public class RankingCoordinator implements Coordinator {
* NotifListBuilder invalidates the notification list each time the ranking is updated,
* so we don't need to explicitly invalidate this filter on ranking update.
*/
- protected final NotifFilter mNotifFilter = new NotifFilter(TAG) {
+ private final NotifFilter mNotifFilter = new NotifFilter(TAG) {
@Override
public boolean shouldFilterOut(NotificationEntry entry, long now) {
// App suspended from Ranking
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java
index 8ebbca26fa5b..3b06220c7c9c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java
@@ -17,10 +17,12 @@
package com.android.systemui.statusbar.notification.logging;
import android.annotation.IntDef;
-import android.service.notification.NotificationListenerService.Ranking;
+import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import com.android.systemui.log.RichEvent;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -31,103 +33,71 @@ import java.lang.annotation.RetentionPolicy;
* here to mitigate memory usage.
*/
public class NotifEvent extends RichEvent {
- public static final int TOTAL_EVENT_TYPES = 11;
-
/**
- * Creates a NotifEvent with an event type that matches with an index in the array
- * getSupportedEvents() and {@link EventType}.
- *
- * The status bar notification and ranking objects are stored as shallow copies of the current
- * state of the event when this event occurred.
+ * Initializes a rich event that includes an event type that matches with an index in the array
+ * getEventLabels().
*/
- public NotifEvent(int logLevel, int type, String reason, StatusBarNotification sbn,
- Ranking ranking) {
- super(logLevel, type, reason);
- mMessage += getExtraInfo(sbn, ranking);
- }
-
- private String getExtraInfo(StatusBarNotification sbn, Ranking ranking) {
- StringBuilder extraInfo = new StringBuilder();
-
+ public NotifEvent init(@EventType int type, StatusBarNotification sbn,
+ NotificationListenerService.Ranking ranking, String reason) {
+ StringBuilder extraInfo = new StringBuilder(reason);
if (sbn != null) {
- extraInfo.append(" Sbn=");
- extraInfo.append(sbn);
+ extraInfo.append(" " + sbn.getKey());
}
if (ranking != null) {
extraInfo.append(" Ranking=");
- extraInfo.append(ranking);
+ extraInfo.append(ranking.getRank());
}
-
- return extraInfo.toString();
+ super.init(INFO, type, extraInfo.toString());
+ return this;
}
/**
- * Event labels for NotifEvents
- * Index corresponds to the {@link EventType}
+ * Event labels for ListBuilderEvents
+ * Index corresponds to an # in {@link EventType}
*/
@Override
public String[] getEventLabels() {
- final String[] events = new String[]{
- "NotifAdded",
- "NotifRemoved",
- "NotifUpdated",
- "Filter",
- "Sort",
- "FilterAndSort",
- "NotifVisibilityChanged",
- "LifetimeExtended",
- "RemoveIntercepted",
- "InflationAborted",
- "Inflated"
- };
-
- if (events.length != TOTAL_EVENT_TYPES) {
- throw new IllegalStateException("NotifEvents events.length should match "
- + TOTAL_EVENT_TYPES
- + " events.length=" + events.length
- + " TOTAL_EVENT_LENGTH=" + TOTAL_EVENT_TYPES);
- }
- return events;
+ assert (TOTAL_EVENT_LABELS == (TOTAL_NEM_EVENT_TYPES + TOTAL_LIST_BUILDER_EVENT_TYPES));
+ return EVENT_LABELS;
}
/**
- * Builds a NotifEvent.
+ * @return if this event occurred in {@link NotifListBuilder}
*/
- public static class NotifEventBuilder extends RichEvent.Builder<NotifEventBuilder> {
- private StatusBarNotification mSbn;
- private Ranking mRanking;
-
- @Override
- public NotifEventBuilder getBuilder() {
- return this;
- }
-
- /**
- * Stores the status bar notification object. A shallow copy is stored in the NotifEvent's
- * constructor.
- */
- public NotifEventBuilder setSbn(StatusBarNotification sbn) {
- mSbn = sbn;
- return this;
- }
+ static boolean isListBuilderEvent(@EventType int type) {
+ return isBetweenInclusive(type, 0, TOTAL_LIST_BUILDER_EVENT_TYPES);
+ }
- /**
- * Stores the ranking object. A shallow copy is stored in the NotifEvent's
- * constructor.
- */
- public NotifEventBuilder setRanking(Ranking ranking) {
- mRanking = ranking;
- return this;
- }
+ /**
+ * @return if this event occurred in {@link NotificationEntryManager}
+ */
+ static boolean isNemEvent(@EventType int type) {
+ return isBetweenInclusive(type, TOTAL_LIST_BUILDER_EVENT_TYPES,
+ TOTAL_LIST_BUILDER_EVENT_TYPES + TOTAL_NEM_EVENT_TYPES);
+ }
- @Override
- public RichEvent build() {
- return new NotifEvent(mLogLevel, mType, mReason, mSbn, mRanking);
- }
+ private static boolean isBetweenInclusive(int x, int a, int b) {
+ return x >= a && x <= b;
}
- @IntDef({NOTIF_ADDED,
+ @IntDef({
+ // NotifListBuilder events:
+ WARN,
+ ON_BUILD_LIST,
+ START_BUILD_LIST,
+ DISPATCH_FINAL_LIST,
+ LIST_BUILD_COMPLETE,
+ FILTER_INVALIDATED,
+ PROMOTER_INVALIDATED,
+ SECTIONS_PROVIDER_INVALIDATED,
+ COMPARATOR_INVALIDATED,
+ PARENT_CHANGED,
+ FILTER_CHANGED,
+ PROMOTER_CHANGED,
+
+ // NotificationEntryManager events:
+ NOTIF_ADDED,
NOTIF_REMOVED,
NOTIF_UPDATED,
FILTER,
@@ -139,22 +109,72 @@ public class NotifEvent extends RichEvent {
INFLATION_ABORTED,
INFLATED
})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface EventType {}
+
+ private static final String[] EVENT_LABELS =
+ new String[]{
+ // NotifListBuilder labels:
+ "Warning",
+ "OnBuildList",
+ "StartBuildList",
+ "DispatchFinalList",
+ "ListBuildComplete",
+ "FilterInvalidated",
+ "PromoterInvalidated",
+ "SectionsProviderInvalidated",
+ "ComparatorInvalidated",
+ "ParentChanged",
+ "FilterChanged",
+ "PromoterChanged",
+
+ // NEM event labels:
+ "NotifAdded",
+ "NotifRemoved",
+ "NotifUpdated",
+ "Filter",
+ "Sort",
+ "FilterAndSort",
+ "NotifVisibilityChanged",
+ "LifetimeExtended",
+ "RemoveIntercepted",
+ "InflationAborted",
+ "Inflated"
+ };
+
+ private static final int TOTAL_EVENT_LABELS = EVENT_LABELS.length;
/**
- * Types of NotifEvents
+ * Events related to {@link NotifListBuilder}
*/
- @Retention(RetentionPolicy.SOURCE)
- public @interface EventType {}
- public static final int NOTIF_ADDED = 0;
- public static final int NOTIF_REMOVED = 1;
- public static final int NOTIF_UPDATED = 2;
- public static final int FILTER = 3;
- public static final int SORT = 4;
- public static final int FILTER_AND_SORT = 5;
- public static final int NOTIF_VISIBILITY_CHANGED = 6;
- public static final int LIFETIME_EXTENDED = 7;
+ public static final int WARN = 0;
+ public static final int ON_BUILD_LIST = 1;
+ public static final int START_BUILD_LIST = 2;
+ public static final int DISPATCH_FINAL_LIST = 3;
+ public static final int LIST_BUILD_COMPLETE = 4;
+ public static final int FILTER_INVALIDATED = 5;
+ public static final int PROMOTER_INVALIDATED = 6;
+ public static final int SECTIONS_PROVIDER_INVALIDATED = 7;
+ public static final int COMPARATOR_INVALIDATED = 8;
+ public static final int PARENT_CHANGED = 9;
+ public static final int FILTER_CHANGED = 10;
+ public static final int PROMOTER_CHANGED = 11;
+ private static final int TOTAL_LIST_BUILDER_EVENT_TYPES = 12;
+
+ /**
+ * Events related to {@link NotificationEntryManager}
+ */
+ public static final int NOTIF_ADDED = TOTAL_LIST_BUILDER_EVENT_TYPES + 0;
+ public static final int NOTIF_REMOVED = TOTAL_LIST_BUILDER_EVENT_TYPES + 1;
+ public static final int NOTIF_UPDATED = TOTAL_LIST_BUILDER_EVENT_TYPES + 2;
+ public static final int FILTER = TOTAL_LIST_BUILDER_EVENT_TYPES + 3;
+ public static final int SORT = TOTAL_LIST_BUILDER_EVENT_TYPES + 4;
+ public static final int FILTER_AND_SORT = TOTAL_LIST_BUILDER_EVENT_TYPES + 5;
+ public static final int NOTIF_VISIBILITY_CHANGED = TOTAL_LIST_BUILDER_EVENT_TYPES + 6;
+ public static final int LIFETIME_EXTENDED = TOTAL_LIST_BUILDER_EVENT_TYPES + 7;
// unable to remove notif - removal intercepted by {@link NotificationRemoveInterceptor}
- public static final int REMOVE_INTERCEPTED = 8;
- public static final int INFLATION_ABORTED = 9;
- public static final int INFLATED = 10;
+ public static final int REMOVE_INTERCEPTED = TOTAL_LIST_BUILDER_EVENT_TYPES + 8;
+ public static final int INFLATION_ABORTED = TOTAL_LIST_BUILDER_EVENT_TYPES + 9;
+ public static final int INFLATED = TOTAL_LIST_BUILDER_EVENT_TYPES + 10;
+ private static final int TOTAL_NEM_EVENT_TYPES = 11;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifLog.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifLog.java
index 129283107894..299d628d0fd2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifLog.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifLog.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.logging;
+import android.os.SystemProperties;
import android.service.notification.NotificationListenerService.Ranking;
import android.service.notification.StatusBarNotification;
@@ -33,93 +34,82 @@ import javax.inject.Singleton;
* dependency DumpController NotifLog
*/
@Singleton
-public class NotifLog extends SysuiLog {
+public class NotifLog extends SysuiLog<NotifEvent> {
private static final String TAG = "NotifLog";
+ private static final boolean SHOW_NEM_LOGS =
+ SystemProperties.getBoolean("persist.sysui.log.notif.nem", true);
+ private static final boolean SHOW_LIST_BUILDER_LOGS =
+ SystemProperties.getBoolean("persist.sysui.log.notif.listbuilder", true);
+
private static final int MAX_DOZE_DEBUG_LOGS = 400;
private static final int MAX_DOZE_LOGS = 50;
+ private NotifEvent mRecycledEvent;
+
@Inject
public NotifLog(DumpController dumpController) {
super(dumpController, TAG, MAX_DOZE_DEBUG_LOGS, MAX_DOZE_LOGS);
}
/**
- * Logs a {@link NotifEvent} with a notification, ranking and message
+ * Logs a {@link NotifEvent} with a notification, ranking and message.
+ * Uses the last recycled event if available.
* @return true if successfully logged, else false
*/
- public boolean log(@NotifEvent.EventType int eventType, StatusBarNotification sbn,
- Ranking ranking, String msg) {
- return log(new NotifEvent.NotifEventBuilder()
- .setType(eventType)
- .setSbn(sbn)
- .setRanking(ranking)
- .setReason(msg)
- .build());
- }
+ public void log(@NotifEvent.EventType int eventType,
+ StatusBarNotification sbn, Ranking ranking, String msg) {
+ if (!mEnabled
+ || (NotifEvent.isListBuilderEvent(eventType) && !SHOW_LIST_BUILDER_LOGS)
+ || (NotifEvent.isNemEvent(eventType) && !SHOW_NEM_LOGS)) {
+ return;
+ }
- /**
- * Logs a {@link NotifEvent}
- * @return true if successfully logged, else false
- */
- public boolean log(@NotifEvent.EventType int eventType) {
- return log(eventType, null, null, null);
+ if (mRecycledEvent != null) {
+ mRecycledEvent = log(mRecycledEvent.init(eventType, sbn, ranking, msg));
+ } else {
+ mRecycledEvent = log(new NotifEvent().init(eventType, sbn, ranking, msg));
+ }
}
/**
- * Logs a {@link NotifEvent} with a message
- * @return true if successfully logged, else false
+ * Logs a {@link NotifEvent} with no extra information aside from the event type
*/
- public boolean log(@NotifEvent.EventType int eventType, String msg) {
- return log(eventType, null, null, msg);
+ public void log(@NotifEvent.EventType int eventType) {
+ log(eventType, null, null, "");
}
/**
- * Logs a {@link NotifEvent} with a notification
- * @return true if successfully logged, else false
- */
- public boolean log(@NotifEvent.EventType int eventType, StatusBarNotification sbn) {
- return log(eventType, sbn, null, "");
- }
-
- /**
- * Logs a {@link NotifEvent} with a notification
- * @return true if successfully logged, else false
+ * Logs a {@link NotifEvent} with a message
*/
- public boolean log(@NotifEvent.EventType int eventType, StatusBarNotification sbn, String msg) {
- return log(eventType, sbn, null, msg);
+ public void log(@NotifEvent.EventType int eventType, String msg) {
+ log(eventType, null, null, msg);
}
/**
- * Logs a {@link NotifEvent} with a ranking
- * @return true if successfully logged, else false
+ * Logs a {@link NotifEvent} with a entry
*/
- public boolean log(@NotifEvent.EventType int eventType, Ranking ranking) {
- return log(eventType, null, ranking, "");
+ public void log(@NotifEvent.EventType int eventType, NotificationEntry entry) {
+ log(eventType, entry.getSbn(), entry.getRanking(), "");
}
/**
- * Logs a {@link NotifEvent} with a notification and ranking
- * @return true if successfully logged, else false
+ * Logs a {@link NotifEvent} with a NotificationEntry and message
*/
- public boolean log(@NotifEvent.EventType int eventType, StatusBarNotification sbn,
- Ranking ranking) {
- return log(eventType, sbn, ranking, "");
+ public void log(@NotifEvent.EventType int eventType, NotificationEntry entry, String msg) {
+ log(eventType, entry.getSbn(), entry.getRanking(), msg);
}
/**
- * Logs a {@link NotifEvent} with a notification entry
- * @return true if successfully logged, else false
+ * Logs a {@link NotifEvent} with a notification and message
*/
- public boolean log(@NotifEvent.EventType int eventType, NotificationEntry entry) {
- return log(eventType, entry.getSbn(), entry.getRanking(), "");
+ public void log(@NotifEvent.EventType int eventType, StatusBarNotification sbn, String msg) {
+ log(eventType, sbn, null, msg);
}
/**
- * Logs a {@link NotifEvent} with a notification entry
- * @return true if successfully logged, else false
+ * Logs a {@link NotifEvent} with a ranking and message
*/
- public boolean log(@NotifEvent.EventType int eventType, NotificationEntry entry,
- String msg) {
- return log(eventType, entry.getSbn(), entry.getRanking(), msg);
+ public void log(@NotifEvent.EventType int eventType, Ranking ranking, String msg) {
+ log(eventType, null, ranking, msg);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 43af3aaa5b84..71342c597bfa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -5519,7 +5519,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
if (viewsToRemove.isEmpty()) {
if (closeShade) {
- mStatusBar.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
+ mShadeController.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
}
return;
}
@@ -5581,7 +5581,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
setDismissAllInProgress(false);
onAnimationComplete.run();
});
- mStatusBar.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
+ mShadeController.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
} else {
setDismissAllInProgress(false);
onAnimationComplete.run();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 865d7e7a6560..250f7300ba56 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -41,6 +41,7 @@ import com.android.systemui.dagger.qualifiers.MainResources;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -136,6 +137,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
private final Handler mHandler;
private final KeyguardBypassController mKeyguardBypassController;
private PowerManager.WakeLock mWakeLock;
+ private final ShadeController mShadeController;
private final KeyguardUpdateMonitor mUpdateMonitor;
private final DozeParameters mDozeParameters;
private final KeyguardStateController mKeyguardStateController;
@@ -159,20 +161,23 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
@Inject
public BiometricUnlockController(Context context, DozeScrimController dozeScrimController,
KeyguardViewMediator keyguardViewMediator, ScrimController scrimController,
- StatusBar statusBar, KeyguardStateController keyguardStateController, Handler handler,
+ StatusBar statusBar, ShadeController shadeController,
+ StatusBarWindowController statusBarWindowController,
+ KeyguardStateController keyguardStateController, Handler handler,
KeyguardUpdateMonitor keyguardUpdateMonitor,
@MainResources Resources resources,
KeyguardBypassController keyguardBypassController, DozeParameters dozeParameters,
MetricsLogger metricsLogger, DumpController dumpController) {
mContext = context;
mPowerManager = context.getSystemService(PowerManager.class);
+ mShadeController = shadeController;
mUpdateMonitor = keyguardUpdateMonitor;
mDozeParameters = dozeParameters;
mUpdateMonitor.registerCallback(this);
mMediaManager = Dependency.get(NotificationMediaManager.class);
Dependency.get(WakefulnessLifecycle.class).addObserver(mWakefulnessObserver);
Dependency.get(ScreenLifecycle.class).addObserver(mScreenObserver);
- mStatusBarWindowController = Dependency.get(StatusBarWindowController.class);
+ mStatusBarWindowController = statusBarWindowController;
mDozeScrimController = dozeScrimController;
mKeyguardViewMediator = keyguardViewMediator;
mScrimController = scrimController;
@@ -358,8 +363,8 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
if (mMode == MODE_SHOW_BOUNCER) {
mStatusBarKeyguardViewManager.showBouncer(false);
}
- mStatusBarKeyguardViewManager.animateCollapsePanels(
- BIOMETRIC_COLLAPSE_SPEEDUP_FACTOR);
+ mShadeController.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */,
+ false /* delayed */, BIOMETRIC_COLLAPSE_SPEEDUP_FACTOR);
mPendingShowBouncer = false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 0703d8c397c7..ebe211754b2b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -164,6 +164,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
private int mDisabledFlags1;
private int mDisabledFlags2;
private final Lazy<StatusBar> mStatusBarLazy;
+ private final ShadeController mShadeController;
private Recents mRecents;
private StatusBar mStatusBar;
private final Divider mDivider;
@@ -216,7 +217,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
mNavigationBarView.getRotationButtonController().setRotateSuggestionButtonState(false);
// Hide the notifications panel when quick step starts
- mStatusBarLazy.get().collapsePanel(true /* animate */);
+ mShadeController.collapsePanel(true /* animate */);
}
@Override
@@ -272,6 +273,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
BroadcastDispatcher broadcastDispatcher,
CommandQueue commandQueue, Divider divider,
Optional<Recents> recentsOptional, Lazy<StatusBar> statusBarLazy,
+ ShadeController shadeController,
@MainHandler Handler mainHandler) {
mAccessibilityManagerWrapper = accessibilityManagerWrapper;
mDeviceProvisionedController = deviceProvisionedController;
@@ -280,6 +282,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
mAssistManager = assistManager;
mSysUiFlagsContainer = sysUiFlagsContainer;
mStatusBarLazy = statusBarLazy;
+ mShadeController = shadeController;
mAssistantAvailable = mAssistManager.getAssistInfoForUser(UserHandle.USER_CURRENT) != null;
mOverviewProxyService = overviewProxyService;
mNavigationModeController = navigationModeController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java
index deea3f17aad0..2fa6795e9df0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java
@@ -32,12 +32,24 @@ public interface ShadeController {
*/
void instantExpandNotificationsPanel();
+ /** See {@link #animateCollapsePanels(int, boolean)}. */
+ void animateCollapsePanels();
+
+ /** See {@link #animateCollapsePanels(int, boolean)}. */
+ void animateCollapsePanels(int flags);
+
/**
* Collapse the shade animated, showing the bouncer when on {@link StatusBarState#KEYGUARD} or
* dismissing {@link StatusBar} when on {@link StatusBarState#SHADE}.
*/
void animateCollapsePanels(int flags, boolean force);
+ /** See {@link #animateCollapsePanels(int, boolean)}. */
+ void animateCollapsePanels(int flags, boolean force, boolean delayed);
+
+ /** See {@link #animateCollapsePanels(int, boolean)}. */
+ void animateCollapsePanels(int flags, boolean force, boolean delayed, float speedUpFactor);
+
/**
* If the notifications panel is not fully expanded, collapse it animated.
*
@@ -61,11 +73,9 @@ public interface ShadeController {
void addPostCollapseAction(Runnable action);
/**
- * Notify the shade controller that the current user changed
- *
- * @param newUserId userId of the new user
+ * Run all of the runnables added by {@link #addPostCollapseAction}.
*/
- void setLockscreenUser(int newUserId);
+ void runPostCollapseRunnables();
/**
* If secure with redaction: Show bouncer, go to unlocked shade.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeControllerImpl.java
new file mode 100644
index 000000000000..57e70141bfcf
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeControllerImpl.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.util.Log;
+import android.view.View;
+import android.view.ViewTreeObserver;
+import android.view.WindowManager;
+
+import com.android.systemui.assist.AssistManager;
+import com.android.systemui.bubbles.BubbleController;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.NotificationPresenter;
+import com.android.systemui.statusbar.StatusBarState;
+
+import java.util.ArrayList;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import dagger.Lazy;
+
+/** An implementation of {@link com.android.systemui.statusbar.phone.ShadeController}. */
+@Singleton
+public class ShadeControllerImpl implements ShadeController {
+
+ private static final String TAG = "ShadeControllerImpl";
+ private static final boolean SPEW = false;
+
+ private final CommandQueue mCommandQueue;
+ private final StatusBarStateController mStatusBarStateController;
+ protected final StatusBarWindowController mStatusBarWindowController;
+ private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+ private final int mDisplayId;
+ protected final Lazy<StatusBar> mStatusBarLazy;
+ private final Lazy<AssistManager> mAssistManagerLazy;
+ private final Lazy<BubbleController> mBubbleControllerLazy;
+
+ private final ArrayList<Runnable> mPostCollapseRunnables = new ArrayList<>();
+
+ @Inject
+ public ShadeControllerImpl(
+ CommandQueue commandQueue,
+ StatusBarStateController statusBarStateController,
+ StatusBarWindowController statusBarWindowController,
+ StatusBarKeyguardViewManager statusBarKeyguardViewManager,
+ WindowManager windowManager,
+ Lazy<StatusBar> statusBarLazy,
+ Lazy<AssistManager> assistManagerLazy,
+ Lazy<BubbleController> bubbleControllerLazy
+ ) {
+ mCommandQueue = commandQueue;
+ mStatusBarStateController = statusBarStateController;
+ mStatusBarWindowController = statusBarWindowController;
+ mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
+ mDisplayId = windowManager.getDefaultDisplay().getDisplayId();
+ // TODO: Remove circular reference to StatusBar when possible.
+ mStatusBarLazy = statusBarLazy;
+ mAssistManagerLazy = assistManagerLazy;
+ mBubbleControllerLazy = bubbleControllerLazy;
+ }
+
+ @Override
+ public void instantExpandNotificationsPanel() {
+ // Make our window larger and the panel expanded.
+ getStatusBar().makeExpandedVisible(true /* force */);
+ getNotificationPanelView().expand(false /* animate */);
+ mCommandQueue.recomputeDisableFlags(mDisplayId, false /* animate */);
+ }
+
+ @Override
+ public void animateCollapsePanels() {
+ animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
+ }
+
+ @Override
+ public void animateCollapsePanels(int flags) {
+ animateCollapsePanels(flags, false /* force */, false /* delayed */,
+ 1.0f /* speedUpFactor */);
+ }
+
+ @Override
+ public void animateCollapsePanels(int flags, boolean force) {
+ animateCollapsePanels(flags, force, false /* delayed */, 1.0f /* speedUpFactor */);
+ }
+
+ @Override
+ public void animateCollapsePanels(int flags, boolean force, boolean delayed) {
+ animateCollapsePanels(flags, force, delayed, 1.0f /* speedUpFactor */);
+ }
+
+ @Override
+ public void animateCollapsePanels(int flags, boolean force, boolean delayed,
+ float speedUpFactor) {
+ if (!force && mStatusBarStateController.getState() != StatusBarState.SHADE) {
+ runPostCollapseRunnables();
+ return;
+ }
+ if (SPEW) {
+ Log.d(TAG, "animateCollapse():"
+ + " mExpandedVisible=" + getStatusBar().isExpandedVisible()
+ + " flags=" + flags);
+ }
+
+ if ((flags & CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL) == 0) {
+ getStatusBar().postHideRecentApps();
+ }
+
+ // TODO(b/62444020): remove when this bug is fixed
+ Log.v(TAG, "mStatusBarWindow: " + getStatusBarWindowView() + " canPanelBeCollapsed(): "
+ + getNotificationPanelView().canPanelBeCollapsed());
+ if (getStatusBarWindowView() != null && getNotificationPanelView().canPanelBeCollapsed()) {
+ // release focus immediately to kick off focus change transition
+ mStatusBarWindowController.setStatusBarFocusable(false);
+
+ getStatusBar().getStatusBarWindowViewController().cancelExpandHelper();
+ getStatusBarView().collapsePanel(true /* animate */, delayed, speedUpFactor);
+ } else {
+ mBubbleControllerLazy.get().collapseStack();
+ }
+ }
+
+
+ @Override
+ public boolean closeShadeIfOpen() {
+ if (!getNotificationPanelView().isFullyCollapsed()) {
+ mCommandQueue.animateCollapsePanels(
+ CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */);
+ getStatusBar().visibilityChanged(false);
+ mAssistManagerLazy.get().hideAssist();
+ }
+ return false;
+ }
+
+ @Override
+ public void postOnShadeExpanded(Runnable executable) {
+ getNotificationPanelView().getViewTreeObserver().addOnGlobalLayoutListener(
+ new ViewTreeObserver.OnGlobalLayoutListener() {
+ @Override
+ public void onGlobalLayout() {
+ if (getStatusBar().getStatusBarWindow().getHeight()
+ != getStatusBar().getStatusBarHeight()) {
+ getNotificationPanelView().getViewTreeObserver()
+ .removeOnGlobalLayoutListener(this);
+ getNotificationPanelView().post(executable);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void addPostCollapseAction(Runnable action) {
+ mPostCollapseRunnables.add(action);
+ }
+
+ @Override
+ public void runPostCollapseRunnables() {
+ ArrayList<Runnable> clonedList = new ArrayList<>(mPostCollapseRunnables);
+ mPostCollapseRunnables.clear();
+ int size = clonedList.size();
+ for (int i = 0; i < size; i++) {
+ clonedList.get(i).run();
+ }
+ mStatusBarKeyguardViewManager.readyForKeyguardDone();
+ }
+
+ @Override
+ public void goToLockedShade(View startingChild) {
+ // TODO: Move this code out of StatusBar into ShadeController.
+ getStatusBar().goToLockedShade(startingChild);
+ }
+
+ @Override
+ public boolean collapsePanel() {
+ if (!getNotificationPanelView().isFullyCollapsed()) {
+ // close the shade if it was open
+ animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
+ true /* force */, true /* delayed */);
+ getStatusBar().visibilityChanged(false);
+
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void collapsePanel(boolean animate) {
+ if (animate) {
+ boolean willCollapse = collapsePanel();
+ if (!willCollapse) {
+ runPostCollapseRunnables();
+ }
+ } else if (!getPresenter().isPresenterFullyCollapsed()) {
+ getStatusBar().instantCollapseNotificationPanel();
+ getStatusBar().visibilityChanged(false);
+ } else {
+ runPostCollapseRunnables();
+ }
+ }
+
+ private StatusBar getStatusBar() {
+ return mStatusBarLazy.get();
+ }
+
+ private NotificationPresenter getPresenter() {
+ return getStatusBar().getPresenter();
+ }
+
+ protected StatusBarWindowView getStatusBarWindowView() {
+ return getStatusBar().getStatusBarWindow();
+ }
+
+ protected PhoneStatusBarView getStatusBarView() {
+ return (PhoneStatusBarView) getStatusBar().getStatusBarView();
+ }
+
+ private NotificationPanelView getNotificationPanelView() {
+ return getStatusBar().getPanel();
+ }
+}
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 e31ad9fd4262..a9d760185fd6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -107,7 +107,6 @@ import android.view.RemoteAnimationAdapter;
import android.view.ThreadedRenderer;
import android.view.View;
import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
import android.view.WindowInsetsController.Appearance;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
@@ -232,7 +231,6 @@ import com.android.systemui.volume.VolumeComponent;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.io.StringWriter;
-import java.util.ArrayList;
import java.util.Map;
import java.util.Optional;
@@ -245,8 +243,7 @@ public class StatusBar extends SystemUI implements DemoMode,
ActivityStarter, KeyguardStateController.Callback,
OnHeadsUpChangedListener, CommandQueue.Callbacks,
ColorExtractor.OnColorsChangedListener, ConfigurationListener,
- StatusBarStateController.StateListener, ShadeController,
- ActivityLaunchAnimator.Callback {
+ StatusBarStateController.StateListener, ActivityLaunchAnimator.Callback {
public static final boolean MULTIUSER_DEBUG = false;
public static final boolean ENABLE_CHILD_NOTIFICATIONS
@@ -387,6 +384,7 @@ public class StatusBar extends SystemUI implements DemoMode,
private final Optional<Divider> mDividerOptional;
private final StatusBarNotificationActivityStarter.Builder
mStatusBarNotificationActivityStarterBuilder;
+ private final ShadeController mShadeController;
private final SuperStatusBarViewFactory mSuperStatusBarViewFactory;
private final LightsOutNotifController mLightsOutNotifController;
private final DismissCallbackRegistry mDismissCallbackRegistry;
@@ -409,7 +407,6 @@ public class StatusBar extends SystemUI implements DemoMode,
private boolean mExpandedVisible;
private final int[] mAbsPos = new int[2];
- private final ArrayList<Runnable> mPostCollapseRunnables = new ArrayList<>();
private final NotificationGutsManager mGutsManager;
private final NotificationLogger mNotificationLogger;
@@ -683,6 +680,7 @@ public class StatusBar extends SystemUI implements DemoMode,
LightsOutNotifController lightsOutNotifController,
StatusBarNotificationActivityStarter.Builder
statusBarNotificationActivityStarterBuilder,
+ ShadeController shadeController,
SuperStatusBarViewFactory superStatusBarViewFactory,
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
ViewMediatorCallback viewMediatorCallback,
@@ -754,6 +752,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mRemoteInputUriController = remoteInputUriController;
mDividerOptional = dividerOptional;
mStatusBarNotificationActivityStarterBuilder = statusBarNotificationActivityStarterBuilder;
+ mShadeController = shadeController;
mSuperStatusBarViewFactory = superStatusBarViewFactory;
mLightsOutNotifController = lightsOutNotifController;
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
@@ -1240,7 +1239,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mScrimController, mActivityLaunchAnimator, mDynamicPrivacyController,
mNotificationAlertingManager, rowBinder, mKeyguardStateController,
mKeyguardIndicationController,
- this /* statusBar */, mCommandQueue);
+ this /* statusBar */, mShadeController, mCommandQueue);
mNotificationListController =
new NotificationListController(
@@ -1318,7 +1317,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mRemoteInputManager.checkRemoteInputOutside(event);
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (mExpandedVisible) {
- animateCollapsePanels();
+ mShadeController.animateCollapsePanels();
}
}
return mStatusBarWindow.onTouchEvent(event);
@@ -1419,6 +1418,10 @@ public class StatusBar extends SystemUI implements DemoMode,
return mStatusBarWindow;
}
+ public StatusBarWindowViewController getStatusBarWindowViewController() {
+ return mStatusBarWindowViewController;
+ }
+
protected ViewGroup getBouncerContainer() {
return mStatusBarWindow;
}
@@ -1574,7 +1577,7 @@ public class StatusBar extends SystemUI implements DemoMode,
if ((diff1 & StatusBarManager.DISABLE_EXPAND) != 0) {
if ((state1 & StatusBarManager.DISABLE_EXPAND) != 0) {
- animateCollapsePanels();
+ mShadeController.animateCollapsePanels();
}
}
@@ -1598,7 +1601,7 @@ public class StatusBar extends SystemUI implements DemoMode,
if ((diff2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0) {
updateQsExpansionEnabled();
if ((state1 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0) {
- animateCollapsePanels();
+ mShadeController.animateCollapsePanels();
}
}
}
@@ -1840,7 +1843,7 @@ public class StatusBar extends SystemUI implements DemoMode,
&& !mActivityLaunchAnimator.isLaunchForActivity()) {
onClosingFinished();
} else {
- collapsePanel(true /* animate */);
+ mShadeController.collapsePanel(true /* animate */);
}
}
@@ -1888,7 +1891,7 @@ public class StatusBar extends SystemUI implements DemoMode,
animateExpandSettingsPanel((String) m.obj);
break;
case MSG_CLOSE_PANELS:
- animateCollapsePanels();
+ mShadeController.animateCollapsePanels();
break;
case MSG_LAUNCH_TRANSITION_TIMEOUT:
onLaunchTransitionTimeout();
@@ -1985,20 +1988,13 @@ public class StatusBar extends SystemUI implements DemoMode,
setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true);
}
- public void animateCollapsePanels() {
- animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
- }
-
- private final Runnable mAnimateCollapsePanels = this::animateCollapsePanels;
-
public void postAnimateCollapsePanels() {
- mHandler.post(mAnimateCollapsePanels);
+ mHandler.post(mShadeController::animateCollapsePanels);
}
public void postAnimateForceCollapsePanels() {
- mHandler.post(() -> {
- animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */);
- });
+ mHandler.post(() -> mShadeController.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE,
+ true /* force */));
}
public void postAnimateOpenPanels() {
@@ -2008,67 +2004,35 @@ public class StatusBar extends SystemUI implements DemoMode,
@Override
public void togglePanel() {
if (mPanelExpanded) {
- animateCollapsePanels();
+ mShadeController.animateCollapsePanels();
} else {
animateExpandNotificationsPanel();
}
}
- public void animateCollapsePanels(int flags) {
- animateCollapsePanels(flags, false /* force */, false /* delayed */,
- 1.0f /* speedUpFactor */);
- }
-
@Override
public void animateCollapsePanels(int flags, boolean force) {
- animateCollapsePanels(flags, force, false /* delayed */, 1.0f /* speedUpFactor */);
- }
-
- public void animateCollapsePanels(int flags, boolean force, boolean delayed) {
- animateCollapsePanels(flags, force, delayed, 1.0f /* speedUpFactor */);
+ mShadeController.animateCollapsePanels(flags, force, false /* delayed */,
+ 1.0f /* speedUpFactor */);
}
- public void animateCollapsePanels(int flags, boolean force, boolean delayed,
- float speedUpFactor) {
- if (!force && mState != StatusBarState.SHADE) {
- runPostCollapseRunnables();
- return;
- }
- if (SPEW) {
- Log.d(TAG, "animateCollapse():"
- + " mExpandedVisible=" + mExpandedVisible
- + " flags=" + flags);
- }
-
- if ((flags & CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL) == 0) {
- if (!mHandler.hasMessages(MSG_HIDE_RECENT_APPS)) {
- mHandler.removeMessages(MSG_HIDE_RECENT_APPS);
- mHandler.sendEmptyMessage(MSG_HIDE_RECENT_APPS);
- }
+ /**
+ * Called by {@link ShadeController} when it calls
+ * {@link ShadeController#animateCollapsePanels(int, boolean, boolean, float)}.
+ */
+ void postHideRecentApps() {
+ if (!mHandler.hasMessages(MSG_HIDE_RECENT_APPS)) {
+ mHandler.removeMessages(MSG_HIDE_RECENT_APPS);
+ mHandler.sendEmptyMessage(MSG_HIDE_RECENT_APPS);
}
+ }
- // TODO(b/62444020): remove when this bug is fixed
- Log.v(TAG, "mStatusBarWindow: " + mStatusBarWindow + " canPanelBeCollapsed(): "
- + mNotificationPanel.canPanelBeCollapsed());
- if (mStatusBarWindow != null && mNotificationPanel.canPanelBeCollapsed()) {
- // release focus immediately to kick off focus change transition
- mStatusBarWindowController.setStatusBarFocusable(false);
-
- mStatusBarWindowViewController.cancelExpandHelper();
- mStatusBarView.collapsePanel(true /* animate */, delayed, speedUpFactor);
- } else {
- mBubbleController.collapseStack();
- }
+ public boolean isExpandedVisible() {
+ return mExpandedVisible;
}
- private void runPostCollapseRunnables() {
- ArrayList<Runnable> clonedList = new ArrayList<>(mPostCollapseRunnables);
- mPostCollapseRunnables.clear();
- int size = clonedList.size();
- for (int i = 0; i < size; i++) {
- clonedList.get(i).run();
- }
- mStatusBarKeyguardViewManager.readyForKeyguardDone();
+ public boolean isPanelExpanded() {
+ return mPanelExpanded;
}
/**
@@ -2147,7 +2111,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mGutsManager.closeAndSaveGuts(true /* removeLeavebehind */, true /* force */,
true /* removeControls */, -1 /* x */, -1 /* y */, true /* resetMenu */);
- runPostCollapseRunnables();
+ mShadeController.runPostCollapseRunnables();
setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
if (!mNotificationActivityStarter.isCollapsingToShowActivityOverLockscreen()) {
showBouncerIfKeyguard();
@@ -2672,12 +2636,12 @@ public class StatusBar extends SystemUI implements DemoMode,
}
if (dismissShade) {
if (mExpandedVisible && !mBouncerShowing) {
- animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */,
- true /* delayed*/);
+ mShadeController.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
+ true /* force */, true /* delayed*/);
} else {
// Do it after DismissAction has been processed to conserve the needed ordering.
- mHandler.post(this::runPostCollapseRunnables);
+ mHandler.post(mShadeController::runPostCollapseRunnables);
}
} else if (isInLaunchTransition() && mNotificationPanel.isLaunchTransitionFinished()) {
@@ -2709,7 +2673,7 @@ public class StatusBar extends SystemUI implements DemoMode,
if (reason != null && reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) {
flags |= CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL;
}
- animateCollapsePanels(flags);
+ mShadeController.animateCollapsePanels(flags);
}
}
else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
@@ -2803,7 +2767,11 @@ public class StatusBar extends SystemUI implements DemoMode,
mScreenPinningRequest.onConfigurationChanged();
}
- @Override
+ /**
+ * Notify the shade controller that the current user changed
+ *
+ * @param newUserId userId of the new user
+ */
public void setLockscreenUser(int newUserId) {
if (mLockscreenWallpaper != null) {
mLockscreenWallpaper.setCurrentUser(newUserId);
@@ -3145,7 +3113,7 @@ public class StatusBar extends SystemUI implements DemoMode,
private void updatePanelExpansionForKeyguard() {
if (mState == StatusBarState.KEYGUARD && mBiometricUnlockController.getMode()
!= BiometricUnlockController.MODE_WAKE_AND_UNLOCK && !mBouncerShowing) {
- instantExpandNotificationsPanel();
+ mShadeController.instantExpandNotificationsPanel();
} else if (mState == StatusBarState.FULLSCREEN_USER_SWITCHER) {
instantCollapseNotificationPanel();
}
@@ -3160,10 +3128,6 @@ public class StatusBar extends SystemUI implements DemoMode,
mPresenter.updateMediaMetaData(true /* metaDataChanged */, true);
}
- public void addPostCollapseAction(Runnable r) {
- mPostCollapseRunnables.add(r);
- }
-
public boolean isInLaunchTransition() {
return mNotificationPanel.isLaunchTransitionRunning()
|| mNotificationPanel.isLaunchTransitionFinished();
@@ -3396,7 +3360,7 @@ public class StatusBar extends SystemUI implements DemoMode,
public boolean onMenuPressed() {
if (shouldUnlockOnMenuPressed()) {
- animateCollapsePanels(
+ mShadeController.animateCollapsePanels(
CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL /* flags */, true /* force */);
return true;
}
@@ -3426,7 +3390,7 @@ public class StatusBar extends SystemUI implements DemoMode,
}
if (mState != StatusBarState.KEYGUARD && mState != StatusBarState.SHADE_LOCKED) {
if (mNotificationPanel.canPanelBeCollapsed()) {
- animateCollapsePanels();
+ mShadeController.animateCollapsePanels();
} else {
mBubbleController.performBackPressIfNeeded();
}
@@ -3440,7 +3404,7 @@ public class StatusBar extends SystemUI implements DemoMode,
public boolean onSpacePressed() {
if (mDeviceInteractive && mState != StatusBarState.SHADE) {
- animateCollapsePanels(
+ mShadeController.animateCollapsePanels(
CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL /* flags */, true /* force */);
return true;
}
@@ -3454,43 +3418,9 @@ public class StatusBar extends SystemUI implements DemoMode,
}
}
- @Override
- public void instantExpandNotificationsPanel() {
- // Make our window larger and the panel expanded.
- makeExpandedVisible(true);
- mNotificationPanel.expand(false /* animate */);
- mCommandQueue.recomputeDisableFlags(mDisplayId, false /* animate */);
- }
-
- @Override
- public boolean closeShadeIfOpen() {
- if (!mNotificationPanel.isFullyCollapsed()) {
- mCommandQueue.animateCollapsePanels(
- CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */);
- visibilityChanged(false);
- mAssistManagerLazy.get().hideAssist();
- }
- return false;
- }
-
- @Override
- public void postOnShadeExpanded(Runnable executable) {
- mNotificationPanel.getViewTreeObserver().addOnGlobalLayoutListener(
- new ViewTreeObserver.OnGlobalLayoutListener() {
- @Override
- public void onGlobalLayout() {
- if (getStatusBarWindow().getHeight() != getStatusBarHeight()) {
- mNotificationPanel.getViewTreeObserver()
- .removeOnGlobalLayoutListener(this);
- mNotificationPanel.post(executable);
- }
- }
- });
- }
-
- private void instantCollapseNotificationPanel() {
+ void instantCollapseNotificationPanel() {
mNotificationPanel.instantCollapse();
- runPostCollapseRunnables();
+ mShadeController.runPostCollapseRunnables();
}
@Override
@@ -3576,11 +3506,11 @@ public class StatusBar extends SystemUI implements DemoMode,
}
public void onTrackingStarted() {
- runPostCollapseRunnables();
+ mShadeController.runPostCollapseRunnables();
}
public void onClosingFinished() {
- runPostCollapseRunnables();
+ mShadeController.runPostCollapseRunnables();
if (!mPresenter.isPresenterFullyCollapsed()) {
// if we set it not to be focusable when collapsing, we have to undo it when we aborted
// the closing
@@ -3641,7 +3571,7 @@ public class StatusBar extends SystemUI implements DemoMode,
*
* @param expandView The view to expand after going to the shade.
*/
- public void goToLockedShade(View expandView) {
+ void goToLockedShade(View expandView) {
if ((mDisabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0) {
return;
}
@@ -3700,7 +3630,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mStatusBarWindowViewController.cancelCurrentTouch();
}
if (mPanelExpanded && mState == StatusBarState.SHADE) {
- animateCollapsePanels();
+ mShadeController.animateCollapsePanels();
}
}
@@ -4067,7 +3997,7 @@ public class StatusBar extends SystemUI implements DemoMode,
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0);
if (BANNER_ACTION_SETUP.equals(action)) {
- animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
+ mShadeController.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
true /* force */);
mContext.startActivity(new Intent(Settings.ACTION_APP_NOTIFICATION_REDACTION)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
@@ -4078,35 +4008,6 @@ public class StatusBar extends SystemUI implements DemoMode,
}
};
- @Override
- public void collapsePanel(boolean animate) {
- if (animate) {
- boolean willCollapse = collapsePanel();
- if (!willCollapse) {
- runPostCollapseRunnables();
- }
- } else if (!mPresenter.isPresenterFullyCollapsed()) {
- instantCollapseNotificationPanel();
- visibilityChanged(false);
- } else {
- runPostCollapseRunnables();
- }
- }
-
- @Override
- public boolean collapsePanel() {
- if (!mNotificationPanel.isFullyCollapsed()) {
- // close the shade if it was open
- animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */,
- true /* delayed */);
- visibilityChanged(false);
-
- return true;
- } else {
- return false;
- }
- }
-
private final NotificationListener mNotificationListener;
public void setNotificationSnoozed(StatusBarNotification sbn, SnoozeOption snoozeOption) {
@@ -4217,7 +4118,7 @@ public class StatusBar extends SystemUI implements DemoMode,
action.run();
}).start();
- return collapsePanel();
+ return mShadeController.collapsePanel();
}, afterKeyguardGone);
}
@@ -4277,7 +4178,7 @@ public class StatusBar extends SystemUI implements DemoMode,
return options.toBundle();
}
- protected void visibilityChanged(boolean visible) {
+ void visibilityChanged(boolean visible) {
if (mVisible != visible) {
mVisible = visible;
if (!visible) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index dac4e585c1ac..f51174b55b74 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -48,7 +48,6 @@ import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.system.QuickStepContract;
-import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.RemoteInputController;
@@ -921,12 +920,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
mStatusBar.keyguardGoingAway();
}
- public void animateCollapsePanels(float speedUpFactor) {
- mStatusBar.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */,
- false /* delayed */, speedUpFactor);
- }
-
-
/**
* Called when cancel button in bouncer is pressed.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java
index 312c85f01275..e31c53abe988 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java
@@ -164,6 +164,7 @@ public class StatusBarModule {
LightsOutNotifController lightsOutNotifController,
StatusBarNotificationActivityStarter.Builder
statusBarNotificationActivityStarterBuilder,
+ ShadeController shadeController,
SuperStatusBarViewFactory superStatusBarViewFactory,
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
ViewMediatorCallback viewMediatorCallback,
@@ -237,6 +238,7 @@ public class StatusBarModule {
dividerOptional,
lightsOutNotifController,
statusBarNotificationActivityStarterBuilder,
+ shadeController,
superStatusBarViewFactory,
statusBarKeyguardViewManager,
viewMediatorCallback,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index 1988b42be14f..3123f8dacada 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -524,7 +524,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
private final ActivityIntentHelper mActivityIntentHelper;
private final BubbleController mBubbleController;
private final SuperStatusBarViewFactory mSuperStatusBarViewFactory;
- private ShadeController mShadeController;
+ private final ShadeController mShadeController;
private NotificationPresenter mNotificationPresenter;
private ActivityLaunchAnimator mActivityLaunchAnimator;
private StatusBar mStatusBar;
@@ -553,6 +553,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
@BgHandler Handler backgroundHandler,
ActivityIntentHelper activityIntentHelper,
BubbleController bubbleController,
+ ShadeController shadeController,
SuperStatusBarViewFactory superStatusBarViewFactory) {
mContext = context;
mCommandQueue = commandQueue;
@@ -577,13 +578,13 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
mBackgroundHandler = backgroundHandler;
mActivityIntentHelper = activityIntentHelper;
mBubbleController = bubbleController;
+ mShadeController = shadeController;
mSuperStatusBarViewFactory = superStatusBarViewFactory;
}
- /** Sets the status bar to use as {@link StatusBar} and {@link ShadeController}. */
+ /** Sets the status bar to use as {@link StatusBar}. */
public Builder setStatusBar(StatusBar statusBar) {
mStatusBar = statusBar;
- mShadeController = statusBar;
return this;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index 2649166bfcbf..8fc624dc9096 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -88,7 +88,6 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
private static final String TAG = "StatusBarNotificationPresenter";
- private final ShadeController mShadeController = Dependency.get(ShadeController.class);
private final ActivityStarter mActivityStarter = Dependency.get(ActivityStarter.class);
private final KeyguardStateController mKeyguardStateController;
private final NotificationViewHierarchyManager mViewHierarchyManager =
@@ -116,6 +115,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
private final Context mContext;
private final KeyguardIndicationController mKeyguardIndicationController;
private final StatusBar mStatusBar;
+ private final ShadeController mShadeController;
private final CommandQueue mCommandQueue;
private final AccessibilityManager mAccessibilityManager;
@@ -145,6 +145,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
KeyguardStateController keyguardStateController,
KeyguardIndicationController keyguardIndicationController,
StatusBar statusBar,
+ ShadeController shadeController,
CommandQueue commandQueue) {
mContext = context;
mKeyguardStateController = keyguardStateController;
@@ -154,6 +155,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
mKeyguardIndicationController = keyguardIndicationController;
// TODO: use KeyguardStateController#isOccluded to remove this dependency
mStatusBar = statusBar;
+ mShadeController = shadeController;
mCommandQueue = commandQueue;
mAboveShelfObserver = new AboveShelfObserver(stackScroller);
mActivityLaunchAnimator = activityLaunchAnimator;
@@ -387,7 +389,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
}
updateNotificationViews();
mMediaManager.clearCurrentMediaNotification();
- mShadeController.setLockscreenUser(newUserId);
+ mStatusBar.setLockscreenUser(newUserId);
updateMediaMetaData(true, false);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
index 2012b5703504..6193a8e9005b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
@@ -50,8 +50,6 @@ import com.android.systemui.statusbar.policy.KeyguardStateController;
import javax.inject.Inject;
import javax.inject.Singleton;
-import dagger.Lazy;
-
/**
*/
@Singleton
@@ -62,9 +60,9 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks,
private final SysuiStatusBarStateController mStatusBarStateController;
private final NotificationLockscreenUserManager mLockscreenUserManager;
private final ActivityStarter mActivityStarter;
- private final Lazy<ShadeController> mShadeControllerLazy;
private final Context mContext;
private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+ private final ShadeController mShadeController;
private final ActivityIntentHelper mActivityIntentHelper;
private final NotificationGroupManager mGroupManager;
private View mPendingWorkRemoteInputView;
@@ -83,16 +81,16 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks,
KeyguardStateController keyguardStateController,
StatusBarStateController statusBarStateController,
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
- ActivityStarter activityStarter, Lazy<ShadeController> shadeControllerLazy,
+ ActivityStarter activityStarter, ShadeController shadeController,
CommandQueue commandQueue) {
mContext = context;
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
+ mShadeController = shadeController;
mContext.registerReceiverAsUser(mChallengeReceiver, UserHandle.ALL,
new IntentFilter(ACTION_DEVICE_LOCKED_CHANGED), null, null);
mLockscreenUserManager = notificationLockscreenUserManager;
mKeyguardStateController = keyguardStateController;
mStatusBarStateController = (SysuiStatusBarStateController) statusBarStateController;
- mShadeControllerLazy = shadeControllerLazy;
mActivityStarter = activityStarter;
mStatusBarStateController.addCallback(this);
mKeyguardManager = context.getSystemService(KeyguardManager.class);
@@ -167,8 +165,8 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks,
});
}
};
- mShadeControllerLazy.get().postOnShadeExpanded(clickPendingViewRunnable);
- mShadeControllerLazy.get().instantExpandNotificationsPanel();
+ mShadeController.postOnShadeExpanded(clickPendingViewRunnable);
+ mShadeController.instantExpandNotificationsPanel();
}
}
@@ -256,7 +254,7 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks,
boolean handled = defaultHandler.handleClick();
// close the shade if it was open and maybe wait for activity start.
- return handled && mShadeControllerLazy.get().closeShadeIfOpen();
+ return handled && mShadeController.closeShadeIfOpen();
}, null, afterKeyguardGone);
return true;
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java
index f8929e01adb8..eb86bcc8a52f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java
@@ -57,12 +57,9 @@ import java.io.PrintWriter;
import javax.inject.Inject;
-import dagger.Lazy;
-
/**
* Controller for {@link StatusBarWindowView}.
*/
-//@Singleton
public class StatusBarWindowViewController {
private final InjectionInflationController mInjectionInflationController;
private final NotificationWakeUpCoordinator mCoordinator;
@@ -80,7 +77,7 @@ public class StatusBarWindowViewController {
private final DozeParameters mDozeParameters;
private final CommandQueue mCommandQueue;
private final StatusBarWindowView mView;
- private final Lazy<ShadeController> mShadeControllerLazy;
+ private final ShadeController mShadeController;
private GestureDetector mGestureDetector;
private View mBrightnessMirror;
@@ -114,7 +111,7 @@ public class StatusBarWindowViewController {
DozeLog dozeLog,
DozeParameters dozeParameters,
CommandQueue commandQueue,
- Lazy<ShadeController> shadeControllerLazy,
+ ShadeController shadeController,
DockManager dockManager,
StatusBarWindowView statusBarWindowView) {
mInjectionInflationController = injectionInflationController;
@@ -133,7 +130,7 @@ public class StatusBarWindowViewController {
mDozeParameters = dozeParameters;
mCommandQueue = commandQueue;
mView = statusBarWindowView;
- mShadeControllerLazy = shadeControllerLazy;
+ mShadeController = shadeController;
mDockManager = dockManager;
// This view is not part of the newly inflated expanded status bar.
@@ -153,7 +150,7 @@ public class StatusBarWindowViewController {
mBypassController,
mFalsingManager,
mPluginManager,
- mShadeControllerLazy.get(),
+ mShadeController,
mNotificationLockscreenUserManager,
mNotificationEntryManager,
mKeyguardStateController,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index b0cd90c3fb76..a6108a490331 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -91,7 +91,8 @@ public class MobileSignalController extends SignalController<
@VisibleForTesting
boolean mIsShowingIconGracefully = false;
// Some specific carriers have 5GE network which is special LTE CA network.
- private static final int NETWORK_TYPE_LTE_CA_5GE = TelephonyManager.MAX_NETWORK_TYPE + 1;
+ private static final int NETWORK_TYPE_LTE_CA_5GE =
+ TelephonyManager.getAllNetworkTypes().length + 1;
// TODO: Reduce number of vars passed in, if we have the NetworkController, probably don't
// need listener lists anymore.
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
index 2f13f395d057..367d4d2bcfa0 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
@@ -16,19 +16,13 @@
package com.android.systemui.usb;
-import android.app.Activity;
import android.app.AlertDialog;
-import android.content.BroadcastReceiver;
-import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
-import android.content.IntentFilter;
import android.debug.IAdbManager;
-import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.os.IBinder;
import android.os.ServiceManager;
-import android.os.SystemProperties;
import android.util.EventLog;
import android.util.Log;
import android.view.LayoutInflater;
@@ -42,25 +36,14 @@ import android.widget.Toast;
import com.android.internal.app.AlertActivity;
import com.android.internal.app.AlertController;
import com.android.systemui.R;
-import com.android.systemui.broadcast.BroadcastDispatcher;
-
-import javax.inject.Inject;
public class UsbDebuggingActivity extends AlertActivity
implements DialogInterface.OnClickListener {
private static final String TAG = "UsbDebuggingActivity";
private CheckBox mAlwaysAllow;
- private UsbDisconnectedReceiver mDisconnectedReceiver;
- private final BroadcastDispatcher mBroadcastDispatcher;
private String mKey;
- @Inject
- public UsbDebuggingActivity(BroadcastDispatcher broadcastDispatcher) {
- super();
- mBroadcastDispatcher = broadcastDispatcher;
- }
-
@Override
public void onCreate(Bundle icicle) {
Window window = getWindow();
@@ -70,10 +53,6 @@ public class UsbDebuggingActivity extends AlertActivity
super.onCreate(icicle);
- if (SystemProperties.getInt("service.adb.tcp.port", 0) == 0) {
- mDisconnectedReceiver = new UsbDisconnectedReceiver(this);
- }
-
Intent intent = getIntent();
String fingerprints = intent.getStringExtra("fingerprints");
mKey = intent.getStringExtra("key");
@@ -126,40 +105,6 @@ public class UsbDebuggingActivity extends AlertActivity
super.onWindowAttributesChanged(params);
}
- private class UsbDisconnectedReceiver extends BroadcastReceiver {
- private final Activity mActivity;
- public UsbDisconnectedReceiver(Activity activity) {
- mActivity = activity;
- }
-
- @Override
- public void onReceive(Context content, Intent intent) {
- String action = intent.getAction();
- if (!UsbManager.ACTION_USB_STATE.equals(action)) {
- return;
- }
- boolean connected = intent.getBooleanExtra(UsbManager.USB_CONNECTED, false);
- if (!connected) {
- mActivity.finish();
- }
- }
- }
-
- @Override
- public void onStart() {
- super.onStart();
- IntentFilter filter = new IntentFilter(UsbManager.ACTION_USB_STATE);
- mBroadcastDispatcher.registerReceiver(mDisconnectedReceiver, filter);
- }
-
- @Override
- protected void onStop() {
- if (mDisconnectedReceiver != null) {
- mBroadcastDispatcher.unregisterReceiver(mDisconnectedReceiver);
- }
- super.onStop();
- }
-
@Override
public void onClick(DialogInterface dialog, int which) {
boolean allow = (which == AlertDialog.BUTTON_POSITIVE);
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingSecondaryUserActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingSecondaryUserActivity.java
index 032b72ebff7d..421424206370 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingSecondaryUserActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingSecondaryUserActivity.java
@@ -16,41 +16,19 @@
package com.android.systemui.usb;
-import android.app.Activity;
-import android.content.BroadcastReceiver;
-import android.content.Context;
import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.hardware.usb.UsbManager;
import android.os.Bundle;
-import android.os.SystemProperties;
import com.android.internal.app.AlertActivity;
import com.android.internal.app.AlertController;
import com.android.systemui.R;
-import com.android.systemui.broadcast.BroadcastDispatcher;
-
-import javax.inject.Inject;
public class UsbDebuggingSecondaryUserActivity extends AlertActivity
implements DialogInterface.OnClickListener {
- private UsbDisconnectedReceiver mDisconnectedReceiver;
- private final BroadcastDispatcher mBroadcastDispatcher;
-
- @Inject
- public UsbDebuggingSecondaryUserActivity(BroadcastDispatcher broadcastDispatcher) {
- mBroadcastDispatcher = broadcastDispatcher;
- }
-
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
- if (SystemProperties.getInt("service.adb.tcp.port", 0) == 0) {
- mDisconnectedReceiver = new UsbDisconnectedReceiver(this);
- }
-
final AlertController.AlertParams ap = mAlertParams;
ap.mTitle = getString(R.string.usb_debugging_secondary_user_title);
ap.mMessage = getString(R.string.usb_debugging_secondary_user_message);
@@ -60,40 +38,6 @@ public class UsbDebuggingSecondaryUserActivity extends AlertActivity
setupAlert();
}
- private class UsbDisconnectedReceiver extends BroadcastReceiver {
- private final Activity mActivity;
- public UsbDisconnectedReceiver(Activity activity) {
- mActivity = activity;
- }
-
- @Override
- public void onReceive(Context content, Intent intent) {
- String action = intent.getAction();
- if (UsbManager.ACTION_USB_STATE.equals(action)) {
- boolean connected = intent.getBooleanExtra(UsbManager.USB_CONNECTED, false);
- if (!connected) {
- mActivity.finish();
- }
- }
- }
- }
-
- @Override
- public void onStart() {
- super.onStart();
-
- IntentFilter filter = new IntentFilter(UsbManager.ACTION_USB_STATE);
- mBroadcastDispatcher.registerReceiver(mDisconnectedReceiver, filter);
- }
-
- @Override
- protected void onStop() {
- if (mDisconnectedReceiver != null) {
- mBroadcastDispatcher.unregisterReceiver(mDisconnectedReceiver);
- }
- super.onStop();
- }
-
@Override
public void onClick(DialogInterface dialog, int which) {
finish();
diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayLayout.java b/packages/SystemUI/src/com/android/systemui/wm/DisplayLayout.java
new file mode 100644
index 000000000000..264a683f6a3d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wm/DisplayLayout.java
@@ -0,0 +1,474 @@
+/*
+ * Copyright (C) 2019 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.wm;
+
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.content.res.Configuration.UI_MODE_TYPE_CAR;
+import static android.content.res.Configuration.UI_MODE_TYPE_MASK;
+import static android.os.Process.SYSTEM_UID;
+import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS;
+import static android.view.Display.FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS;
+import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
+
+import android.annotation.NonNull;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Rect;
+import android.os.SystemProperties;
+import android.provider.Settings;
+import android.util.Size;
+import android.view.Display;
+import android.view.DisplayCutout;
+import android.view.DisplayInfo;
+import android.view.Gravity;
+import android.view.Surface;
+
+import com.android.internal.R;
+
+import java.util.List;
+
+/**
+ * Contains information about the layout-properties of a display. This refers to internal layout
+ * like insets/cutout/rotation. In general, this can be thought of as the System-UI analog to
+ * DisplayPolicy.
+ */
+public class DisplayLayout {
+ // Navigation bar position values
+ private static final int NAV_BAR_LEFT = 1 << 0;
+ private static final int NAV_BAR_RIGHT = 1 << 1;
+ private static final int NAV_BAR_BOTTOM = 1 << 2;
+
+ private int mUiMode;
+ private int mWidth;
+ private int mHeight;
+ private DisplayCutout mCutout;
+ private int mRotation;
+ private int mDensityDpi;
+ private final Rect mNonDecorInsets = new Rect();
+ private final Rect mStableInsets = new Rect();
+ private boolean mHasNavigationBar = false;
+ private boolean mHasStatusBar = false;
+
+ /**
+ * Create empty layout.
+ */
+ public DisplayLayout() {
+ }
+
+ /**
+ * Construct a custom display layout using a DisplayInfo.
+ * @param info
+ * @param res
+ */
+ public DisplayLayout(DisplayInfo info, Resources res, boolean hasNavigationBar,
+ boolean hasStatusBar) {
+ init(info, res, hasNavigationBar, hasStatusBar);
+ }
+
+ /**
+ * Construct a display layout based on a live display.
+ * @param context Used for resources.
+ */
+ public DisplayLayout(@NonNull Context context, @NonNull Display rawDisplay) {
+ final int displayId = rawDisplay.getDisplayId();
+ DisplayInfo info = new DisplayInfo();
+ rawDisplay.getDisplayInfo(info);
+ init(info, context.getResources(), hasNavigationBar(info, context, displayId),
+ hasStatusBar(displayId));
+ }
+
+ public DisplayLayout(DisplayLayout dl) {
+ set(dl);
+ }
+
+ /** sets this DisplayLayout to a copy of another on. */
+ public void set(DisplayLayout dl) {
+ mUiMode = dl.mUiMode;
+ mWidth = dl.mWidth;
+ mHeight = dl.mHeight;
+ mCutout = dl.mCutout;
+ mRotation = dl.mRotation;
+ mDensityDpi = dl.mDensityDpi;
+ mHasNavigationBar = dl.mHasNavigationBar;
+ mHasStatusBar = dl.mHasStatusBar;
+ mNonDecorInsets.set(dl.mNonDecorInsets);
+ mStableInsets.set(dl.mStableInsets);
+ }
+
+ private void init(DisplayInfo info, Resources res, boolean hasNavigationBar,
+ boolean hasStatusBar) {
+ mUiMode = res.getConfiguration().uiMode;
+ mWidth = info.logicalWidth;
+ mHeight = info.logicalHeight;
+ mRotation = info.rotation;
+ mCutout = info.displayCutout;
+ mDensityDpi = info.logicalDensityDpi;
+ mHasNavigationBar = hasNavigationBar;
+ mHasStatusBar = hasStatusBar;
+ recalcInsets(res);
+ }
+
+ private void recalcInsets(Resources res) {
+ computeNonDecorInsets(res, mRotation, mWidth, mHeight, mCutout, mUiMode, mNonDecorInsets,
+ mHasNavigationBar);
+ mStableInsets.set(mNonDecorInsets);
+ if (mHasStatusBar) {
+ convertNonDecorInsetsToStableInsets(res, mStableInsets, mWidth, mHeight, mHasStatusBar);
+ }
+ }
+
+ /**
+ * Apply a rotation to this layout and its parameters.
+ * @param res
+ * @param targetRotation
+ */
+ public void rotateTo(Resources res, @Surface.Rotation int targetRotation) {
+ final int rotationDelta = (targetRotation - mRotation + 4) % 4;
+ final boolean changeOrient = (rotationDelta % 2) != 0;
+
+ final int origWidth = mWidth;
+ final int origHeight = mHeight;
+
+ mRotation = targetRotation;
+ if (changeOrient) {
+ mWidth = origHeight;
+ mHeight = origWidth;
+ }
+
+ if (mCutout != null && !mCutout.isEmpty()) {
+ mCutout = calculateDisplayCutoutForRotation(mCutout, rotationDelta, origWidth,
+ origHeight);
+ }
+
+ recalcInsets(res);
+ }
+
+ /** Get this layout's non-decor insets. */
+ public Rect nonDecorInsets() {
+ return mNonDecorInsets;
+ }
+
+ /** Get this layout's stable insets. */
+ public Rect stableInsets() {
+ return mStableInsets;
+ }
+
+ /** Get this layout's width. */
+ public int width() {
+ return mWidth;
+ }
+
+ /** Get this layout's height. */
+ public int height() {
+ return mHeight;
+ }
+
+ /** Get this layout's display rotation. */
+ public int rotation() {
+ return mRotation;
+ }
+
+ /** Get this layout's display density. */
+ public int densityDpi() {
+ return mDensityDpi;
+ }
+
+ /** Get whether this layout is landscape. */
+ public boolean isLandscape() {
+ return mWidth > mHeight;
+ }
+
+ /** Gets the orientation of this layout */
+ public int getOrientation() {
+ return (mWidth > mHeight) ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT;
+ }
+
+ /** Gets the calculated stable-bounds for this layout */
+ public void getStableBounds(Rect outBounds) {
+ outBounds.set(0, 0, mWidth, mHeight);
+ outBounds.inset(mStableInsets);
+ }
+
+ /**
+ * Rotates bounds as if parentBounds and bounds are a group. The group is rotated by `delta`
+ * 90-degree counter-clockwise increments. This assumes that parentBounds is at 0,0 and
+ * remains at 0,0 after rotation.
+ *
+ * Only 'bounds' is mutated.
+ */
+ public static void rotateBounds(Rect inOutBounds, Rect parentBounds, int delta) {
+ int rdelta = ((delta % 4) + 4) % 4;
+ int origLeft = inOutBounds.left;
+ switch (rdelta) {
+ case 0:
+ return;
+ case 1:
+ inOutBounds.left = inOutBounds.top;
+ inOutBounds.top = parentBounds.right - inOutBounds.right;
+ inOutBounds.right = inOutBounds.bottom;
+ inOutBounds.bottom = parentBounds.right - origLeft;
+ return;
+ case 2:
+ inOutBounds.left = parentBounds.right - inOutBounds.right;
+ inOutBounds.right = parentBounds.right - origLeft;
+ return;
+ case 3:
+ inOutBounds.left = parentBounds.bottom - inOutBounds.bottom;
+ inOutBounds.bottom = inOutBounds.right;
+ inOutBounds.right = parentBounds.bottom - inOutBounds.top;
+ inOutBounds.top = origLeft;
+ return;
+ }
+ }
+
+ /**
+ * Calculates the stable insets if we already have the non-decor insets.
+ */
+ private static void convertNonDecorInsetsToStableInsets(Resources res, Rect inOutInsets,
+ int displayWidth, int displayHeight, boolean hasStatusBar) {
+ if (!hasStatusBar) {
+ return;
+ }
+ int statusBarHeight = getStatusBarHeight(displayWidth > displayHeight, res);
+ inOutInsets.top = Math.max(inOutInsets.top, statusBarHeight);
+ }
+
+ /**
+ * Calculates the insets for the areas that could never be removed in Honeycomb, i.e. system
+ * bar or button bar.
+ *
+ * @param displayRotation the current display rotation
+ * @param displayWidth the current display width
+ * @param displayHeight the current display height
+ * @param displayCutout the current display cutout
+ * @param outInsets the insets to return
+ */
+ static void computeNonDecorInsets(Resources res, int displayRotation, int displayWidth,
+ int displayHeight, DisplayCutout displayCutout, int uiMode, Rect outInsets,
+ boolean hasNavigationBar) {
+ outInsets.setEmpty();
+
+ // Only navigation bar
+ if (hasNavigationBar) {
+ int position = navigationBarPosition(res, displayWidth, displayHeight, displayRotation);
+ int navBarSize =
+ getNavigationBarSize(res, position, displayWidth > displayHeight, uiMode);
+ if (position == NAV_BAR_BOTTOM) {
+ outInsets.bottom = navBarSize;
+ } else if (position == NAV_BAR_RIGHT) {
+ outInsets.right = navBarSize;
+ } else if (position == NAV_BAR_LEFT) {
+ outInsets.left = navBarSize;
+ }
+ }
+
+ if (displayCutout != null) {
+ outInsets.left += displayCutout.getSafeInsetLeft();
+ outInsets.top += displayCutout.getSafeInsetTop();
+ outInsets.right += displayCutout.getSafeInsetRight();
+ outInsets.bottom += displayCutout.getSafeInsetBottom();
+ }
+ }
+
+ /**
+ * Calculates the stable insets without running a layout.
+ *
+ * @param displayRotation the current display rotation
+ * @param displayWidth the current display width
+ * @param displayHeight the current display height
+ * @param displayCutout the current display cutout
+ * @param outInsets the insets to return
+ */
+ static void computeStableInsets(Resources res, int displayRotation, int displayWidth,
+ int displayHeight, DisplayCutout displayCutout, int uiMode, Rect outInsets,
+ boolean hasNavigationBar, boolean hasStatusBar) {
+ outInsets.setEmpty();
+
+ // Navigation bar and status bar.
+ computeNonDecorInsets(res, displayRotation, displayWidth, displayHeight, displayCutout,
+ uiMode, outInsets, hasNavigationBar);
+ convertNonDecorInsetsToStableInsets(res, outInsets, displayWidth, displayHeight,
+ hasStatusBar);
+ }
+
+ /** Retrieve the statusbar height from resources. */
+ static int getStatusBarHeight(boolean landscape, Resources res) {
+ return landscape ? res.getDimensionPixelSize(
+ com.android.internal.R.dimen.status_bar_height_landscape)
+ : res.getDimensionPixelSize(
+ com.android.internal.R.dimen.status_bar_height_portrait);
+ }
+
+ /** Calculate the DisplayCutout for a particular display size/rotation. */
+ public static DisplayCutout calculateDisplayCutoutForRotation(
+ DisplayCutout cutout, int rotation, int displayWidth, int displayHeight) {
+ if (cutout == null || cutout == DisplayCutout.NO_CUTOUT) {
+ return null;
+ }
+ if (rotation == ROTATION_0) {
+ return computeSafeInsets(
+ cutout, displayWidth, displayHeight);
+ }
+ final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
+ Rect[] cutoutRects = computeSafeInsets(cutout, displayWidth, displayHeight)
+ .getBoundingRectsAll();
+ final Rect[] newBounds = new Rect[cutoutRects.length];
+ final Rect displayBounds = new Rect(0, 0, displayWidth, displayHeight);
+ for (int i = 0; i < cutoutRects.length; ++i) {
+ newBounds[i] = new Rect(cutoutRects[i]);
+ rotateBounds(newBounds[i], displayBounds, rotation);
+ }
+ return computeSafeInsets(DisplayCutout.fromBounds(newBounds),
+ rotated ? displayHeight : displayWidth,
+ rotated ? displayWidth : displayHeight);
+ }
+
+ /** Calculate safe insets. */
+ public static DisplayCutout computeSafeInsets(DisplayCutout inner,
+ int displayWidth, int displayHeight) {
+ if (inner == DisplayCutout.NO_CUTOUT || inner.isBoundsEmpty()) {
+ return null;
+ }
+
+ final Size displaySize = new Size(displayWidth, displayHeight);
+ final Rect safeInsets = computeSafeInsets(displaySize, inner);
+ return inner.replaceSafeInsets(safeInsets);
+ }
+
+ private static Rect computeSafeInsets(Size displaySize, DisplayCutout cutout) {
+ if (displaySize.getWidth() < displaySize.getHeight()) {
+ final List<Rect> boundingRects = cutout.replaceSafeInsets(
+ new Rect(0, displaySize.getHeight() / 2, 0, displaySize.getHeight() / 2))
+ .getBoundingRects();
+ int topInset = findInsetForSide(displaySize, boundingRects, Gravity.TOP);
+ int bottomInset = findInsetForSide(displaySize, boundingRects, Gravity.BOTTOM);
+ return new Rect(0, topInset, 0, bottomInset);
+ } else if (displaySize.getWidth() > displaySize.getHeight()) {
+ final List<Rect> boundingRects = cutout.replaceSafeInsets(
+ new Rect(displaySize.getWidth() / 2, 0, displaySize.getWidth() / 2, 0))
+ .getBoundingRects();
+ int leftInset = findInsetForSide(displaySize, boundingRects, Gravity.LEFT);
+ int right = findInsetForSide(displaySize, boundingRects, Gravity.RIGHT);
+ return new Rect(leftInset, 0, right, 0);
+ } else {
+ throw new UnsupportedOperationException("not implemented: display=" + displaySize
+ + " cutout=" + cutout);
+ }
+ }
+
+ private static int findInsetForSide(Size display, List<Rect> boundingRects, int gravity) {
+ int inset = 0;
+ final int size = boundingRects.size();
+ for (int i = 0; i < size; i++) {
+ Rect boundingRect = boundingRects.get(i);
+ switch (gravity) {
+ case Gravity.TOP:
+ if (boundingRect.top == 0) {
+ inset = Math.max(inset, boundingRect.bottom);
+ }
+ break;
+ case Gravity.BOTTOM:
+ if (boundingRect.bottom == display.getHeight()) {
+ inset = Math.max(inset, display.getHeight() - boundingRect.top);
+ }
+ break;
+ case Gravity.LEFT:
+ if (boundingRect.left == 0) {
+ inset = Math.max(inset, boundingRect.right);
+ }
+ break;
+ case Gravity.RIGHT:
+ if (boundingRect.right == display.getWidth()) {
+ inset = Math.max(inset, display.getWidth() - boundingRect.left);
+ }
+ break;
+ default:
+ throw new IllegalArgumentException("unknown gravity: " + gravity);
+ }
+ }
+ return inset;
+ }
+
+ static boolean hasNavigationBar(DisplayInfo info, Context context, int displayId) {
+ if (displayId == Display.DEFAULT_DISPLAY) {
+ // Allow a system property to override this. Used by the emulator.
+ final String navBarOverride = SystemProperties.get("qemu.hw.mainkeys");
+ if ("1".equals(navBarOverride)) {
+ return false;
+ } else if ("0".equals(navBarOverride)) {
+ return true;
+ }
+ return context.getResources().getBoolean(R.bool.config_showNavigationBar);
+ } else {
+ boolean isUntrustedVirtualDisplay = info.type == Display.TYPE_VIRTUAL
+ && info.ownerUid != SYSTEM_UID;
+ final ContentResolver resolver = context.getContentResolver();
+ boolean forceDesktopOnExternal = Settings.Global.getInt(resolver,
+ DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS, 0) != 0;
+
+ return ((info.flags & FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS) != 0
+ || (forceDesktopOnExternal && !isUntrustedVirtualDisplay));
+ // TODO(b/142569966): make sure VR2D and DisplayWindowSettings are moved here somehow.
+ }
+ }
+
+ static boolean hasStatusBar(int displayId) {
+ return displayId == Display.DEFAULT_DISPLAY;
+ }
+
+ /** Retrieve navigation bar position from resources based on rotation and size. */
+ public static int navigationBarPosition(Resources res, int displayWidth, int displayHeight,
+ int rotation) {
+ boolean navBarCanMove = displayWidth != displayHeight && res.getBoolean(
+ com.android.internal.R.bool.config_navBarCanMove);
+ if (navBarCanMove && displayWidth > displayHeight) {
+ if (rotation == Surface.ROTATION_90) {
+ return NAV_BAR_RIGHT;
+ } else {
+ return NAV_BAR_LEFT;
+ }
+ }
+ return NAV_BAR_BOTTOM;
+ }
+
+ /** Retrieve navigation bar size from resources based on side/orientation/ui-mode */
+ public static int getNavigationBarSize(Resources res, int navBarSide, boolean landscape,
+ int uiMode) {
+ final boolean carMode = (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR;
+ if (carMode) {
+ if (navBarSide == NAV_BAR_BOTTOM) {
+ return res.getDimensionPixelSize(landscape
+ ? R.dimen.navigation_bar_height_landscape_car_mode
+ : R.dimen.navigation_bar_height_car_mode);
+ } else {
+ return res.getDimensionPixelSize(R.dimen.navigation_bar_width_car_mode);
+ }
+ } else {
+ if (navBarSide == NAV_BAR_BOTTOM) {
+ return res.getDimensionPixelSize(landscape
+ ? R.dimen.navigation_bar_height_landscape
+ : R.dimen.navigation_bar_height);
+ } else {
+ return res.getDimensionPixelSize(R.dimen.navigation_bar_width);
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayWindowController.java b/packages/SystemUI/src/com/android/systemui/wm/DisplayWindowController.java
index 19fff79671d4..ae82115ca37e 100644
--- a/packages/SystemUI/src/com/android/systemui/wm/DisplayWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/wm/DisplayWindowController.java
@@ -16,16 +16,20 @@
package com.android.systemui.wm;
+import android.annotation.Nullable;
+import android.content.Context;
import android.content.res.Configuration;
+import android.hardware.display.DisplayManager;
import android.os.Handler;
import android.os.RemoteException;
import android.util.Slog;
import android.util.SparseArray;
+import android.view.Display;
import android.view.IDisplayWindowListener;
import android.view.IDisplayWindowRotationCallback;
import android.view.IDisplayWindowRotationController;
+import android.view.IWindowManager;
import android.view.WindowContainerTransaction;
-import android.view.WindowManagerGlobal;
import com.android.systemui.dagger.qualifiers.MainHandler;
@@ -45,6 +49,8 @@ public class DisplayWindowController {
private static final String TAG = "DisplayWindowController";
private final Handler mHandler;
+ private final Context mContext;
+ private final IWindowManager mWmService;
private final ArrayList<OnDisplayWindowRotationController> mRotationControllers =
new ArrayList<>();
@@ -76,6 +82,14 @@ public class DisplayWindowController {
}
};
+ /**
+ * Get's a display by id from DisplayManager.
+ */
+ public Display getDisplay(int displayId) {
+ final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
+ return displayManager.getDisplay(displayId);
+ }
+
private final IDisplayWindowListener mDisplayContainerListener =
new IDisplayWindowListener.Stub() {
@Override
@@ -87,6 +101,10 @@ public class DisplayWindowController {
}
DisplayRecord record = new DisplayRecord();
record.mDisplayId = displayId;
+ Display display = getDisplay(displayId);
+ record.mContext = (displayId == Display.DEFAULT_DISPLAY) ? mContext
+ : mContext.createDisplayContext(display);
+ record.mDisplayLayout = new DisplayLayout(record.mContext, display);
mDisplays.put(displayId, record);
for (int i = 0; i < mDisplayChangedListeners.size(); ++i) {
mDisplayChangedListeners.get(i).onDisplayAdded(displayId);
@@ -105,6 +123,13 @@ public class DisplayWindowController {
+ " display.");
return;
}
+ Display display = getDisplay(displayId);
+ Context perDisplayContext = mContext;
+ if (displayId != Display.DEFAULT_DISPLAY) {
+ perDisplayContext = mContext.createDisplayContext(display);
+ }
+ dr.mContext = perDisplayContext.createConfigurationContext(newConfig);
+ dr.mDisplayLayout = new DisplayLayout(dr.mContext, display);
for (int i = 0; i < mDisplayChangedListeners.size(); ++i) {
mDisplayChangedListeners.get(i).onDisplayConfigurationChanged(
displayId, newConfig);
@@ -127,19 +152,36 @@ public class DisplayWindowController {
};
@Inject
- public DisplayWindowController(@MainHandler Handler mainHandler) {
+ public DisplayWindowController(Context context, @MainHandler Handler mainHandler,
+ IWindowManager wmService) {
mHandler = mainHandler;
+ mContext = context;
+ mWmService = wmService;
try {
- WindowManagerGlobal.getWindowManagerService().registerDisplayWindowListener(
- mDisplayContainerListener);
- WindowManagerGlobal.getWindowManagerService().setDisplayWindowRotationController(
- mDisplayRotationController);
+ mWmService.registerDisplayWindowListener(mDisplayContainerListener);
+ mWmService.setDisplayWindowRotationController(mDisplayRotationController);
} catch (RemoteException e) {
throw new RuntimeException("Unable to register hierarchy listener");
}
}
/**
+ * Gets the DisplayLayout associated with a display.
+ */
+ public @Nullable DisplayLayout getDisplayLayout(int displayId) {
+ final DisplayRecord r = mDisplays.get(displayId);
+ return r != null ? r.mDisplayLayout : null;
+ }
+
+ /**
+ * Gets a display-specific context for a display.
+ */
+ public @Nullable Context getDisplayContext(int displayId) {
+ final DisplayRecord r = mDisplays.get(displayId);
+ return r != null ? r.mContext : null;
+ }
+
+ /**
* Add a display window-container listener. It will get notified whenever a display's
* configuration changes or when displays are added/removed from the WM hierarchy.
*/
@@ -184,6 +226,8 @@ public class DisplayWindowController {
private static class DisplayRecord {
int mDisplayId;
+ Context mContext;
+ DisplayLayout mDisplayLayout;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java b/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java
new file mode 100644
index 000000000000..5ec61c3313f0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java
@@ -0,0 +1,330 @@
+/*
+ * Copyright (C) 2019 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.wm;
+
+import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.util.MergedConfiguration;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.view.Display;
+import android.view.DisplayCutout;
+import android.view.DragEvent;
+import android.view.IWindow;
+import android.view.IWindowManager;
+import android.view.IWindowSession;
+import android.view.IWindowSessionCallback;
+import android.view.InsetsSourceControl;
+import android.view.InsetsState;
+import android.view.SurfaceControl;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.WindowlessViewRoot;
+import android.view.WindowlessWindowManager;
+
+import com.android.internal.os.IResultReceiver;
+
+import java.util.HashMap;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Represents the "windowing" layer of the System-UI. This layer allows system-ui components to
+ * place and manipulate windows without talking to WindowManager.
+ */
+@Singleton
+public class SystemWindows {
+ private static final String TAG = "SystemWindows";
+
+ private final SparseArray<PerDisplay> mPerDisplay = new SparseArray<>();
+ final HashMap<View, WindowlessViewRoot> mViewRoots = new HashMap<>();
+ Context mContext;
+ IWindowSession mSession;
+ DisplayWindowController mDisplayController;
+ IWindowManager mWmService;
+
+ private final DisplayWindowController.DisplayWindowListener mDisplayListener =
+ new DisplayWindowController.DisplayWindowListener() {
+ @Override
+ public void onDisplayAdded(int displayId) { }
+
+ @Override
+ public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
+ PerDisplay pd = mPerDisplay.get(displayId);
+ if (pd == null) {
+ return;
+ }
+ pd.updateConfiguration(newConfig);
+ }
+
+ @Override
+ public void onDisplayRemoved(int displayId) { }
+ };
+
+ @Inject
+ public SystemWindows(Context context, DisplayWindowController displayController,
+ IWindowManager wmService) {
+ mContext = context;
+ mWmService = wmService;
+ mDisplayController = displayController;
+ mDisplayController.addDisplayWindowListener(mDisplayListener);
+ try {
+ mSession = wmService.openSession(
+ new IWindowSessionCallback.Stub() {
+ @Override
+ public void onAnimatorScaleChanged(float scale) {}
+ });
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to create layer", e);
+ }
+ }
+
+ /**
+ * Adds a view to system-ui window management.
+ */
+ public void addView(View view, WindowManager.LayoutParams attrs, int displayId,
+ int windowType) {
+ PerDisplay pd = mPerDisplay.get(displayId);
+ if (pd == null) {
+ pd = new PerDisplay(displayId);
+ mPerDisplay.put(displayId, pd);
+ }
+ pd.addView(view, attrs, windowType);
+ }
+
+ /**
+ * Removes a view from system-ui window management.
+ * @param view
+ */
+ public void removeView(View view) {
+ WindowlessViewRoot root = mViewRoots.remove(view);
+ root.die();
+ }
+
+ /**
+ * Updates the layout params of a view.
+ */
+ public void updateViewLayout(@NonNull View view, ViewGroup.LayoutParams params) {
+ WindowlessViewRoot root = mViewRoots.get(view);
+ if (root == null || !(params instanceof WindowManager.LayoutParams)) {
+ return;
+ }
+ view.setLayoutParams(params);
+ root.relayout((WindowManager.LayoutParams) params);
+ }
+
+ /**
+ * Adds a root for system-ui window management with no views. Only useful for IME.
+ */
+ public void addRoot(int displayId, int windowType) {
+ PerDisplay pd = mPerDisplay.get(displayId);
+ if (pd == null) {
+ pd = new PerDisplay(displayId);
+ mPerDisplay.put(displayId, pd);
+ }
+ pd.addRoot(windowType);
+ }
+
+ /**
+ * Get the IWindow token for a specific root.
+ *
+ * @param windowType A window type from {@link android.view.WindowManager}.
+ */
+ IWindow getWindow(int displayId, int windowType) {
+ PerDisplay pd = mPerDisplay.get(displayId);
+ if (pd == null) {
+ return null;
+ }
+ return pd.getWindow(windowType);
+ }
+
+ private class PerDisplay {
+ final int mDisplayId;
+ private final SparseArray<SysUiWindowManager> mWwms = new SparseArray<>();
+
+ PerDisplay(int displayId) {
+ mDisplayId = displayId;
+ }
+
+ public void addView(View view, WindowManager.LayoutParams attrs, int windowType) {
+ SysUiWindowManager wwm = addRoot(windowType);
+ if (wwm == null) {
+ Slog.e(TAG, "Unable to create systemui root");
+ return;
+ }
+ final Display display = mDisplayController.getDisplay(mDisplayId);
+ WindowlessViewRoot viewRoot = new WindowlessViewRoot(mContext, display, wwm);
+ attrs.flags |= FLAG_HARDWARE_ACCELERATED;
+ viewRoot.addView(view, attrs);
+ mViewRoots.put(view, viewRoot);
+ }
+
+ SysUiWindowManager addRoot(int windowType) {
+ SysUiWindowManager wwm = mWwms.get(windowType);
+ if (wwm != null) {
+ return wwm;
+ }
+ SurfaceControl rootSurface = null;
+ ContainerWindow win = new ContainerWindow();
+ try {
+ rootSurface = mWmService.addShellRoot(mDisplayId, win, windowType);
+ } catch (RemoteException e) {
+ }
+ if (rootSurface == null) {
+ Slog.e(TAG, "Unable to get root surfacecontrol for systemui");
+ return null;
+ }
+ Context displayContext = mDisplayController.getDisplayContext(mDisplayId);
+ wwm = new SysUiWindowManager(mDisplayId, displayContext, rootSurface, win);
+ mWwms.put(windowType, wwm);
+ return wwm;
+ }
+
+ IWindow getWindow(int windowType) {
+ SysUiWindowManager wwm = mWwms.get(windowType);
+ if (wwm == null) {
+ return null;
+ }
+ return wwm.mContainerWindow;
+ }
+
+ void updateConfiguration(Configuration configuration) {
+ for (int i = 0; i < mWwms.size(); ++i) {
+ mWwms.valueAt(i).updateConfiguration(configuration);
+ }
+ }
+ }
+
+ /**
+ * A subclass of WindowlessWindowManager that provides insets to its viewroots.
+ */
+ public class SysUiWindowManager extends WindowlessWindowManager {
+ final int mDisplayId;
+ ContainerWindow mContainerWindow;
+ public SysUiWindowManager(int displayId, Context ctx, SurfaceControl rootSurface,
+ ContainerWindow container) {
+ super(ctx.getResources().getConfiguration(), rootSurface, null /* hostInputToken */);
+ mContainerWindow = container;
+ mDisplayId = displayId;
+ }
+
+ @Override
+ public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs,
+ int requestedWidth, int requestedHeight, int viewVisibility, int flags,
+ long frameNumber, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
+ Rect outVisibleInsets, Rect outStableInsets,
+ DisplayCutout.ParcelableWrapper cutout, MergedConfiguration mergedConfiguration,
+ SurfaceControl outSurfaceControl, InsetsState outInsetsState) {
+ int res = super.relayout(window, seq, attrs, requestedWidth, requestedHeight,
+ viewVisibility, flags, frameNumber, outFrame, outOverscanInsets,
+ outContentInsets, outVisibleInsets, outStableInsets,
+ cutout, mergedConfiguration, outSurfaceControl, outInsetsState);
+ if (res != 0) {
+ return res;
+ }
+ DisplayLayout dl = mDisplayController.getDisplayLayout(mDisplayId);
+ outStableInsets.set(dl.stableInsets());
+ return 0;
+ }
+
+ void updateConfiguration(Configuration configuration) {
+ setConfiguration(configuration);
+ }
+ }
+
+ class ContainerWindow extends IWindow.Stub {
+ ContainerWindow() {}
+
+ @Override
+ public void resized(Rect frame, Rect contentInsets, Rect visibleInsets, Rect stableInsets,
+ boolean reportDraw, MergedConfiguration newMergedConfiguration, Rect backDropFrame,
+ boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId,
+ DisplayCutout.ParcelableWrapper displayCutout) {}
+
+ @Override
+ public void locationInParentDisplayChanged(Point offset) {}
+
+ @Override
+ public void insetsChanged(InsetsState insetsState) {}
+
+ @Override
+ public void insetsControlChanged(InsetsState insetsState,
+ InsetsSourceControl[] activeControls) {}
+
+ @Override
+ public void showInsets(int types, boolean fromIme) {}
+
+ @Override
+ public void hideInsets(int types, boolean fromIme) {}
+
+ @Override
+ public void moved(int newX, int newY) {}
+
+ @Override
+ public void dispatchAppVisibility(boolean visible) {}
+
+ @Override
+ public void dispatchGetNewSurface() {}
+
+ @Override
+ public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {}
+
+ @Override
+ public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {}
+
+ @Override
+ public void closeSystemDialogs(String reason) {}
+
+ @Override
+ public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
+ boolean sync) {}
+
+ @Override
+ public void dispatchWallpaperCommand(String action, int x, int y,
+ int z, Bundle extras, boolean sync) {}
+
+ /* Drag/drop */
+ @Override
+ public void dispatchDragEvent(DragEvent event) {}
+
+ @Override
+ public void updatePointerIcon(float x, float y) {}
+
+ @Override
+ public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
+ int localValue, int localChanges) {}
+
+ @Override
+ public void dispatchWindowShown() {}
+
+ @Override
+ public void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId) {}
+
+ @Override
+ public void dispatchPointerCaptureChanged(boolean hasCapture) {}
+ }
+}
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index 81e2c22d5c4f..e5f56d43f4d7 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -32,7 +32,8 @@ LOCAL_MULTILIB := both
LOCAL_JNI_SHARED_LIBRARIES := \
libdexmakerjvmtiagent \
- libmultiplejvmtiagentsinterferenceagent
+ libmultiplejvmtiagentsinterferenceagent \
+ libstaticjvmtiagent
LOCAL_JAVA_LIBRARIES := \
android.test.runner \
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index e0d31d053f76..2ccececbdd9d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -94,8 +94,6 @@ import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import dagger.Lazy;
-
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@@ -153,7 +151,7 @@ public class BubbleControllerTest extends SysuiTestCase {
@Mock
private Resources mResources;
@Mock
- private Lazy<ShadeController> mShadeController;
+ private ShadeController mShadeController;
@Mock
private RemoteInputUriController mRemoteInputUriController;
@@ -719,7 +717,7 @@ public class BubbleControllerTest extends SysuiTestCase {
TestableBubbleController(Context context,
StatusBarWindowController statusBarWindowController,
StatusBarStateController statusBarStateController,
- Lazy<ShadeController> shadeController,
+ ShadeController shadeController,
BubbleData data,
ConfigurationController configurationController,
NotificationInterruptionStateProvider interruptionStateProvider,
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 cbfcfddba5ab..a8a2b33215e5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -68,15 +68,14 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
mDependency.injectTestDependency(FalsingManager.class, mFalsingManager);
mDependency.injectTestDependency(KeyguardUpdateMonitor.class, mUpdateMonitor);
- mDependency.injectTestDependency(StatusBarWindowController.class,
- mStatusBarWindowController);
when(mLockPatternUtils.getDevicePolicyManager()).thenReturn(mDevicePolicyManager);
TestableLooper.get(this).runWithLooper(() -> {
mViewMediator = new KeyguardViewMediator(
mContext, mFalsingManager, mLockPatternUtils, mBroadcastDispatcher,
- () -> mStatusBarKeyguardViewManager, mDismissCallbackRegistry);
+ mStatusBarWindowController, () -> mStatusBarKeyguardViewManager,
+ mDismissCallbackRegistry);
});
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/RichEventTest.java b/packages/SystemUI/tests/src/com/android/systemui/log/RichEventTest.java
index 2f90641775e8..4a90bb91ca37 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/log/RichEventTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/log/RichEventTest.java
@@ -57,7 +57,7 @@ public class RichEventTest extends SysuiTestCase {
class TestableRichEvent extends RichEvent {
TestableRichEvent(int logLevel, int type, String reason) {
- super(logLevel, type, reason);
+ init(logLevel, type, reason);
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/SysuiLogTest.java b/packages/SystemUI/tests/src/com/android/systemui/log/SysuiLogTest.java
index 1e8ebeafce8a..e7b317e882ef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/log/SysuiLogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/log/SysuiLogTest.java
@@ -35,11 +35,12 @@ import org.mockito.MockitoAnnotations;
@RunWith(AndroidTestingRunner.class)
public class SysuiLogTest extends SysuiTestCase {
private static final String TEST_ID = "TestLogger";
+ private static final String TEST_MSG = "msg";
private static final int MAX_LOGS = 5;
@Mock
private DumpController mDumpController;
- private SysuiLog mSysuiLog;
+ private SysuiLog<Event> mSysuiLog;
@Before
public void setup() {
@@ -48,35 +49,63 @@ public class SysuiLogTest extends SysuiTestCase {
@Test
public void testLogDisabled_noLogsWritten() {
- mSysuiLog = new SysuiLog(mDumpController, TEST_ID, MAX_LOGS, false, false);
- assertEquals(mSysuiLog.mTimeline, null);
+ mSysuiLog = new TestSysuiLog(mDumpController, TEST_ID, MAX_LOGS, false);
+ assertEquals(null, mSysuiLog.mTimeline);
- mSysuiLog.log(new Event("msg"));
- assertEquals(mSysuiLog.mTimeline, null);
+ mSysuiLog.log(createEvent(TEST_MSG));
+ assertEquals(null, mSysuiLog.mTimeline);
}
@Test
public void testLogEnabled_logWritten() {
- mSysuiLog = new SysuiLog(mDumpController, TEST_ID, MAX_LOGS, true, false);
- assertEquals(mSysuiLog.mTimeline.size(), 0);
+ mSysuiLog = new TestSysuiLog(mDumpController, TEST_ID, MAX_LOGS, true);
+ assertEquals(0, mSysuiLog.mTimeline.size());
- mSysuiLog.log(new Event("msg"));
- assertEquals(mSysuiLog.mTimeline.size(), 1);
+ mSysuiLog.log(createEvent(TEST_MSG));
+ assertEquals(1, mSysuiLog.mTimeline.size());
}
@Test
public void testMaxLogs() {
- mSysuiLog = new SysuiLog(mDumpController, TEST_ID, MAX_LOGS, true, false);
+ mSysuiLog = new TestSysuiLog(mDumpController, TEST_ID, MAX_LOGS, true);
assertEquals(mSysuiLog.mTimeline.size(), 0);
- final String msg = "msg";
for (int i = 0; i < MAX_LOGS + 1; i++) {
- mSysuiLog.log(new Event(msg + i));
+ mSysuiLog.log(createEvent(TEST_MSG + i));
}
- assertEquals(mSysuiLog.mTimeline.size(), MAX_LOGS);
+ assertEquals(MAX_LOGS, mSysuiLog.mTimeline.size());
+
+ // check the first message (msg0) was replaced with msg1:
+ assertEquals(TEST_MSG + "1", mSysuiLog.mTimeline.getFirst().getMessage());
+ }
+
+ @Test
+ public void testRecycleLogs() {
+ // GIVEN a SysuiLog with one log
+ mSysuiLog = new TestSysuiLog(mDumpController, TEST_ID, MAX_LOGS, true);
+ Event e = createEvent(TEST_MSG); // msg
+ mSysuiLog.log(e); // Logs: [msg]
+
+ Event recycledEvent = null;
+ // WHEN we add MAX_LOGS after the first log
+ for (int i = 0; i < MAX_LOGS; i++) {
+ recycledEvent = mSysuiLog.log(createEvent(TEST_MSG + i));
+ }
+ // Logs: [msg1, msg2, msg3, msg4]
- // check the first message (msg0) is deleted:
- assertEquals(mSysuiLog.mTimeline.getFirst().getMessage(), msg + "1");
+ // THEN we see the recycledEvent is e
+ assertEquals(e, recycledEvent);
+ }
+
+ private Event createEvent(String msg) {
+ return new Event().init(msg);
+ }
+
+ public class TestSysuiLog extends SysuiLog<Event> {
+ protected TestSysuiLog(DumpController dumpController, String id, int maxLogs,
+ boolean enabled) {
+ super(dumpController, id, maxLogs, enabled, false);
+ }
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
index 46a8dad8c382..07d2e3128d87 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
@@ -53,7 +53,6 @@ import com.android.systemui.statusbar.notification.row.ExpandableView;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
-import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.util.Assert;
import com.google.android.collect.Lists;
@@ -79,7 +78,6 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
@Mock private NotificationLockscreenUserManager mLockscreenUserManager;
@Mock private NotificationGroupManager mGroupManager;
@Mock private VisualStabilityManager mVisualStabilityManager;
- @Mock private ShadeController mShadeController;
private TestableLooper mTestableLooper;
private Handler mHandler;
@@ -99,14 +97,12 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
mLockscreenUserManager);
mDependency.injectTestDependency(NotificationGroupManager.class, mGroupManager);
mDependency.injectTestDependency(VisualStabilityManager.class, mVisualStabilityManager);
- mDependency.injectTestDependency(ShadeController.class, mShadeController);
mHelper = new NotificationTestHelper(mContext, mDependency);
mViewHierarchyManager = new NotificationViewHierarchyManager(mContext,
mHandler, mLockscreenUserManager, mGroupManager, mVisualStabilityManager,
mock(StatusBarStateControllerImpl.class), mEntryManager,
- () -> mShadeController,
mock(KeyguardBypassController.class),
mock(BubbleController.class),
mock(DynamicPrivacyController.class));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImplTest.java
index ffaea156c9d5..bbabb1154e03 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImplTest.java
@@ -47,6 +47,7 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.SectionsProvider;
+import com.android.systemui.statusbar.notification.logging.NotifLog;
import com.android.systemui.util.Assert;
import com.android.systemui.util.time.FakeSystemClock;
@@ -76,6 +77,7 @@ public class NotifListBuilderImplTest extends SysuiTestCase {
private NotifListBuilderImpl mListBuilder;
private FakeSystemClock mSystemClock = new FakeSystemClock();
+ @Mock private NotifLog mNotifLog;
@Mock private NotifCollection mNotifCollection;
@Spy private OnBeforeTransformGroupsListener mOnBeforeTransformGroupsListener;
@Spy private OnBeforeSortListener mOnBeforeSortListener;
@@ -97,7 +99,7 @@ public class NotifListBuilderImplTest extends SysuiTestCase {
MockitoAnnotations.initMocks(this);
Assert.sMainLooper = TestableLooper.get(this).getLooper();
- mListBuilder = new NotifListBuilderImpl(mSystemClock);
+ mListBuilder = new NotifListBuilderImpl(mSystemClock, mNotifLog);
mListBuilder.setOnRenderListListener(mOnRenderListListener);
mListBuilder.attach(mNotifCollection);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinatorTest.java
new file mode 100644
index 000000000000..a9413c78d770
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinatorTest.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.coordinator;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.Manifest;
+import android.app.ActivityManagerInternal;
+import android.app.Notification;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.os.RemoteException;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.NotificationEntryBuilder;
+import com.android.systemui.statusbar.RankingBuilder;
+import com.android.systemui.statusbar.notification.collection.NotifListBuilderImpl;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoSession;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DeviceProvisionedCoordinatorTest extends SysuiTestCase {
+ private static final int NOTIF_UID = 0;
+
+ private static final String SHOW_WHEN_UNPROVISIONED_FLAG =
+ Notification.EXTRA_ALLOW_DURING_SETUP;
+ private static final String SETUP_NOTIF_PERMISSION =
+ Manifest.permission.NOTIFICATION_DURING_SETUP;
+
+ private MockitoSession mMockitoSession;
+
+ @Mock private ActivityManagerInternal mActivityMangerInternal;
+ @Mock private IPackageManager mIPackageManager;
+ @Mock private DeviceProvisionedController mDeviceProvisionedController;
+ @Mock private NotifListBuilderImpl mNotifListBuilder;
+ private Notification mNotification;
+ private NotificationEntry mEntry;
+ private DeviceProvisionedCoordinator mDeviceProvisionedCoordinator;
+ private NotifFilter mDeviceProvisionedFilter;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mDeviceProvisionedCoordinator = new DeviceProvisionedCoordinator(
+ mDeviceProvisionedController, mIPackageManager);
+
+ mNotification = new Notification();
+ mEntry = new NotificationEntryBuilder()
+ .setNotification(mNotification)
+ .setUid(NOTIF_UID)
+ .build();
+
+ ArgumentCaptor<NotifFilter> filterCaptor = ArgumentCaptor.forClass(NotifFilter.class);
+ mDeviceProvisionedCoordinator.attach(null, mNotifListBuilder);
+ verify(mNotifListBuilder, times(1)).addFilter(filterCaptor.capture());
+ mDeviceProvisionedFilter = filterCaptor.getValue();
+ }
+
+ @Test
+ public void deviceProvisioned() {
+ // GIVEN device is provisioned
+ when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true);
+
+ // THEN don't filter out the notification
+ assertFalse(mDeviceProvisionedFilter.shouldFilterOut(mEntry, 0));
+ }
+
+ @Test
+ public void deviceUnprovisioned() {
+ // GIVEN device is unprovisioned
+ when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(false);
+
+ // THEN filter out the notification
+ assertTrue(mDeviceProvisionedFilter.shouldFilterOut(mEntry, 0));
+ }
+
+ @Test
+ public void deviceUnprovisionedCanBypass() throws RemoteException {
+ // GIVEN device is unprovisioned
+ when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(false);
+
+ // GIVEN notification has a flag to allow the notification during setup
+ Bundle extras = new Bundle();
+ extras.putBoolean(SHOW_WHEN_UNPROVISIONED_FLAG, true);
+ mNotification.extras = extras;
+
+ // GIVEN notification has the permission to display during setup
+ when(mIPackageManager.checkUidPermission(SETUP_NOTIF_PERMISSION, NOTIF_UID))
+ .thenReturn(PackageManager.PERMISSION_GRANTED);
+
+ // THEN don't filter out the notification
+ assertFalse(mDeviceProvisionedFilter.shouldFilterOut(mEntry, 0));
+ }
+
+ @Test
+ public void deviceUnprovisionedTryBypassWithoutPermission() throws RemoteException {
+ // GIVEN device is unprovisioned
+ when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(false);
+
+ // GIVEN notification has a flag to allow the notification during setup
+ Bundle extras = new Bundle();
+ extras.putBoolean(SHOW_WHEN_UNPROVISIONED_FLAG, true);
+ mNotification.extras = extras;
+
+ // GIVEN notification does NOT have permission to display during setup
+ when(mIPackageManager.checkUidPermission(SETUP_NOTIF_PERMISSION, NOTIF_UID))
+ .thenReturn(PackageManager.PERMISSION_DENIED);
+
+ // THEN filter out the notification
+ assertTrue(mDeviceProvisionedFilter.shouldFilterOut(mEntry, 0));
+ }
+
+ private RankingBuilder getRankingForUnfilteredNotif() {
+ return new RankingBuilder()
+ .setKey(mEntry.getKey())
+ .setSuppressedVisualEffects(0)
+ .setSuspended(false);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinatorTest.java
new file mode 100644
index 000000000000..ffaa335f91bc
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinatorTest.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.coordinator;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Notification;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.service.notification.NotificationListenerService;
+import android.service.notification.StatusBarNotification;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.ForegroundServiceController;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.appops.AppOpsController;
+import com.android.systemui.statusbar.NotificationEntryBuilder;
+import com.android.systemui.statusbar.notification.collection.NotifCollection;
+import com.android.systemui.statusbar.notification.collection.NotifLifetimeExtender;
+import com.android.systemui.statusbar.notification.collection.NotifListBuilderImpl;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
+
+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)
+public class ForegroundCoordinatorTest extends SysuiTestCase {
+ private static final String TEST_PKG = "test_pkg";
+ private static final int NOTIF_USER_ID = 0;
+
+ @Mock private Handler mMainHandler;
+ @Mock private ForegroundServiceController mForegroundServiceController;
+ @Mock private AppOpsController mAppOpsController;
+ @Mock private NotifListBuilderImpl mNotifListBuilder;
+ @Mock private NotifCollection mNotifCollection;
+
+ private NotificationEntry mEntry;
+ private Notification mNotification;
+ private ForegroundCoordinator mForegroundCoordinator;
+ private NotifFilter mForegroundFilter;
+ private NotifLifetimeExtender mForegroundNotifLifetimeExtender;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mForegroundCoordinator = new ForegroundCoordinator(
+ mForegroundServiceController, mAppOpsController, mMainHandler);
+
+ mNotification = new Notification();
+ mEntry = new NotificationEntryBuilder()
+ .setUser(new UserHandle(NOTIF_USER_ID))
+ .setNotification(mNotification)
+ .build();
+
+ ArgumentCaptor<NotifFilter> filterCaptor = ArgumentCaptor.forClass(NotifFilter.class);
+ ArgumentCaptor<NotifLifetimeExtender> lifetimeExtenderCaptor =
+ ArgumentCaptor.forClass(NotifLifetimeExtender.class);
+
+ mForegroundCoordinator.attach(mNotifCollection, mNotifListBuilder);
+ verify(mNotifListBuilder, times(1)).addFilter(filterCaptor.capture());
+ verify(mNotifCollection, times(1)).addNotificationLifetimeExtender(
+ lifetimeExtenderCaptor.capture());
+
+ mForegroundFilter = filterCaptor.getValue();
+ mForegroundNotifLifetimeExtender = lifetimeExtenderCaptor.getValue();
+ }
+
+ @Test
+ public void filterTest_disclosureUnnecessary() {
+ StatusBarNotification sbn = mEntry.getSbn();
+
+ // GIVEN the notification is a disclosure notification
+ when(mForegroundServiceController.isDisclosureNotification(sbn)).thenReturn(true);
+
+ // GIVEN the disclosure isn't needed for this user
+ when(mForegroundServiceController.isDisclosureNeededForUser(sbn.getUserId()))
+ .thenReturn(false);
+
+ // THEN filter out the notification
+ assertTrue(mForegroundFilter.shouldFilterOut(mEntry, 0));
+ }
+
+ @Test
+ public void filterTest_systemAlertNotificationUnnecessary() {
+ StatusBarNotification sbn = mEntry.getSbn();
+
+ // GIVEN the notification is a system alert notification + not a disclosure notification
+ when(mForegroundServiceController.isSystemAlertNotification(sbn)).thenReturn(true);
+ when(mForegroundServiceController.isDisclosureNotification(sbn)).thenReturn(false);
+
+ // GIVEN the alert notification isn't needed for this user
+ final Bundle extras = new Bundle();
+ extras.putStringArray(Notification.EXTRA_FOREGROUND_APPS,
+ new String[]{TEST_PKG});
+ mNotification.extras = extras;
+ when(mForegroundServiceController.isSystemAlertWarningNeeded(sbn.getUserId(), TEST_PKG))
+ .thenReturn(false);
+
+ // THEN filter out the notification
+ assertTrue(mForegroundFilter.shouldFilterOut(mEntry, 0));
+ }
+
+ @Test
+ public void filterTest_doNotFilter() {
+ StatusBarNotification sbn = mEntry.getSbn();
+
+ // GIVEN the notification isn't a system alert notification nor a disclosure notification
+ when(mForegroundServiceController.isSystemAlertNotification(sbn)).thenReturn(false);
+ when(mForegroundServiceController.isDisclosureNotification(sbn)).thenReturn(false);
+
+ // THEN don't filter out the notification
+ assertFalse(mForegroundFilter.shouldFilterOut(mEntry, 0));
+ }
+
+ @Test
+ public void extendLifetimeText_notForeground() {
+ // GIVEN the notification doesn't represent a foreground service
+ mNotification.flags = 0;
+
+ // THEN don't extend the lifetime
+ assertFalse(mForegroundNotifLifetimeExtender
+ .shouldExtendLifetime(mEntry, NotificationListenerService.REASON_CLICK));
+ }
+
+ @Test
+ public void extendLifetimeText_foregroundNotifRecentlyPosted() {
+ // GIVEN the notification represents a foreground service that was just posted
+ mNotification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
+ mEntry = new NotificationEntryBuilder()
+ .setUser(new UserHandle(NOTIF_USER_ID))
+ .setSbn(new StatusBarNotification(TEST_PKG, TEST_PKG, NOTIF_USER_ID, "",
+ NOTIF_USER_ID, NOTIF_USER_ID, mNotification,
+ new UserHandle(NOTIF_USER_ID), "", System.currentTimeMillis()))
+ .setNotification(mNotification)
+ .build();
+
+ // THEN extend the lifetime
+ assertTrue(mForegroundNotifLifetimeExtender
+ .shouldExtendLifetime(mEntry, NotificationListenerService.REASON_CLICK));
+ }
+
+ @Test
+ public void extendLifetimeText_foregroundNotifOld() {
+ // GIVEN the notification represents a foreground service that was posted 10 seconds ago
+ mNotification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
+ mEntry = new NotificationEntryBuilder()
+ .setUser(new UserHandle(NOTIF_USER_ID))
+ .setSbn(new StatusBarNotification(TEST_PKG, TEST_PKG, NOTIF_USER_ID, "",
+ NOTIF_USER_ID, NOTIF_USER_ID, mNotification,
+ new UserHandle(NOTIF_USER_ID), "",
+ System.currentTimeMillis() - 10000))
+ .setNotification(mNotification)
+ .build();
+
+ // THEN don't extend the lifetime because the extended time exceeds
+ // ForegroundCoordinator.MIN_FGS_TIME_MS
+ assertFalse(mForegroundNotifLifetimeExtender
+ .shouldExtendLifetime(mEntry, NotificationListenerService.REASON_CLICK));
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
index 87b3783d1984..527370e46b6e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
@@ -24,6 +24,8 @@ import static android.app.NotificationManager.IMPORTANCE_MIN;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.os.Handler;
@@ -40,12 +42,15 @@ import com.android.systemui.statusbar.NotificationEntryBuilder;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.RankingBuilder;
import com.android.systemui.statusbar.notification.collection.GroupEntry;
+import com.android.systemui.statusbar.notification.collection.NotifListBuilderImpl;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.policy.KeyguardStateController;
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;
@@ -61,14 +66,16 @@ public class KeyguardCoordinatorTest extends SysuiTestCase {
@Mock private BroadcastDispatcher mBroadcastDispatcher;
@Mock private StatusBarStateController mStatusBarStateController;
@Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ @Mock private NotifListBuilderImpl mNotifListBuilder;
private NotificationEntry mEntry;
- private KeyguardCoordinator mKeyguardNotificationCoordinator;
+ private KeyguardCoordinator mKeyguardCoordinator;
+ private NotifFilter mKeyguardFilter;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
- mKeyguardNotificationCoordinator = new KeyguardCoordinator(
+ mKeyguardCoordinator = new KeyguardCoordinator(
mContext, mMainHandler, mKeyguardStateController, mLockscreenUserManager,
mBroadcastDispatcher, mStatusBarStateController,
mKeyguardUpdateMonitor);
@@ -76,6 +83,11 @@ public class KeyguardCoordinatorTest extends SysuiTestCase {
mEntry = new NotificationEntryBuilder()
.setUser(new UserHandle(NOTIF_USER_ID))
.build();
+
+ ArgumentCaptor<NotifFilter> filterCaptor = ArgumentCaptor.forClass(NotifFilter.class);
+ mKeyguardCoordinator.attach(null, mNotifListBuilder);
+ verify(mNotifListBuilder, times(1)).addFilter(filterCaptor.capture());
+ mKeyguardFilter = filterCaptor.getValue();
}
@Test
@@ -84,7 +96,7 @@ public class KeyguardCoordinatorTest extends SysuiTestCase {
setupUnfilteredState();
// THEN don't filter out the entry
- assertFalse(mKeyguardNotificationCoordinator.mNotifFilter.shouldFilterOut(mEntry, 0));
+ assertFalse(mKeyguardFilter.shouldFilterOut(mEntry, 0));
}
@Test
@@ -94,7 +106,7 @@ public class KeyguardCoordinatorTest extends SysuiTestCase {
when(mLockscreenUserManager.isCurrentProfile(NOTIF_USER_ID)).thenReturn(false);
// THEN filter out the entry
- assertTrue(mKeyguardNotificationCoordinator.mNotifFilter.shouldFilterOut(mEntry, 0));
+ assertTrue(mKeyguardFilter.shouldFilterOut(mEntry, 0));
}
@Test
@@ -104,7 +116,7 @@ public class KeyguardCoordinatorTest extends SysuiTestCase {
when(mKeyguardStateController.isShowing()).thenReturn(false);
// THEN don't filter out the entry
- assertFalse(mKeyguardNotificationCoordinator.mNotifFilter.shouldFilterOut(mEntry, 0));
+ assertFalse(mKeyguardFilter.shouldFilterOut(mEntry, 0));
}
@Test
@@ -116,7 +128,7 @@ public class KeyguardCoordinatorTest extends SysuiTestCase {
when(mLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn(false);
// THEN filter out the entry
- assertTrue(mKeyguardNotificationCoordinator.mNotifFilter.shouldFilterOut(mEntry, 0));
+ assertTrue(mKeyguardFilter.shouldFilterOut(mEntry, 0));
}
@Test
@@ -128,7 +140,7 @@ public class KeyguardCoordinatorTest extends SysuiTestCase {
when(mKeyguardUpdateMonitor.isUserInLockdown(NOTIF_USER_ID)).thenReturn(true);
// THEN filter out the entry
- assertTrue(mKeyguardNotificationCoordinator.mNotifFilter.shouldFilterOut(mEntry, 0));
+ assertTrue(mKeyguardFilter.shouldFilterOut(mEntry, 0));
}
@Test
@@ -143,7 +155,7 @@ public class KeyguardCoordinatorTest extends SysuiTestCase {
.thenReturn(false);
// THEN filter out the entry
- assertTrue(mKeyguardNotificationCoordinator.mNotifFilter.shouldFilterOut(mEntry, 0));
+ assertTrue(mKeyguardFilter.shouldFilterOut(mEntry, 0));
}
@Test
@@ -159,7 +171,7 @@ public class KeyguardCoordinatorTest extends SysuiTestCase {
.setVisibilityOverride(VISIBILITY_SECRET).build());
// THEN filter out the entry
- assertTrue(mKeyguardNotificationCoordinator.mNotifFilter.shouldFilterOut(mEntry, 0));
+ assertTrue(mKeyguardFilter.shouldFilterOut(mEntry, 0));
}
@Test
@@ -174,7 +186,7 @@ public class KeyguardCoordinatorTest extends SysuiTestCase {
.build());
// THEN filter out the entry
- assertTrue(mKeyguardNotificationCoordinator.mNotifFilter.shouldFilterOut(mEntry, 0));
+ assertTrue(mKeyguardFilter.shouldFilterOut(mEntry, 0));
}
@Test
@@ -199,7 +211,7 @@ public class KeyguardCoordinatorTest extends SysuiTestCase {
mEntry.setParent(group);
// THEN don't filter out the entry
- assertFalse(mKeyguardNotificationCoordinator.mNotifFilter.shouldFilterOut(mEntry, 0));
+ assertFalse(mKeyguardFilter.shouldFilterOut(mEntry, 0));
}
/**
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java
new file mode 100644
index 000000000000..182e86667c63
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.coordinator;
+
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.NotificationEntryBuilder;
+import com.android.systemui.statusbar.RankingBuilder;
+import com.android.systemui.statusbar.notification.collection.NotifListBuilderImpl;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
+
+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)
+public class RankingCoordinatorTest extends SysuiTestCase {
+
+ @Mock private StatusBarStateController mStatusBarStateController;
+ @Mock private NotifListBuilderImpl mNotifListBuilder;
+ private NotificationEntry mEntry;
+ private RankingCoordinator mRankingCoordinator;
+ private NotifFilter mRankingFilter;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mRankingCoordinator = new RankingCoordinator(mStatusBarStateController);
+ mEntry = new NotificationEntryBuilder().build();
+
+ ArgumentCaptor<NotifFilter> filterCaptor = ArgumentCaptor.forClass(NotifFilter.class);
+ mRankingCoordinator.attach(null, mNotifListBuilder);
+ verify(mNotifListBuilder, times(1)).addFilter(filterCaptor.capture());
+ mRankingFilter = filterCaptor.getValue();
+ }
+
+ @Test
+ public void testUnfilteredState() {
+ // GIVEN no suppressed visual effects + app not suspended
+ mEntry.setRanking(getRankingForUnfilteredNotif().build());
+
+ // THEN don't filter out the notification
+ assertFalse(mRankingFilter.shouldFilterOut(mEntry, 0));
+ }
+
+ @Test
+ public void filterSuspended() {
+ // GIVEN the notification's app is suspended
+ mEntry.setRanking(getRankingForUnfilteredNotif()
+ .setSuspended(true)
+ .build());
+
+ // THEN filter out the notification
+ assertTrue(mRankingFilter.shouldFilterOut(mEntry, 0));
+ }
+
+ @Test
+ public void filterDozingSuppressAmbient() {
+ // GIVEN should suppress ambient
+ mEntry.setRanking(getRankingForUnfilteredNotif()
+ .setSuppressedVisualEffects(SUPPRESSED_EFFECT_AMBIENT)
+ .build());
+
+ // WHEN it's dozing (on ambient display)
+ when(mStatusBarStateController.isDozing()).thenReturn(true);
+
+ // THEN filter out the notification
+ assertTrue(mRankingFilter.shouldFilterOut(mEntry, 0));
+
+ // WHEN it's not dozing (showing the notification list)
+ when(mStatusBarStateController.isDozing()).thenReturn(false);
+
+ // THEN don't filter out the notification
+ assertFalse(mRankingFilter.shouldFilterOut(mEntry, 0));
+ }
+
+ @Test
+ public void filterDozingSuppressNotificationList() {
+ // GIVEN should suppress from the notification list
+ mEntry.setRanking(getRankingForUnfilteredNotif()
+ .setSuppressedVisualEffects(SUPPRESSED_EFFECT_NOTIFICATION_LIST)
+ .build());
+
+ // WHEN it's dozing (on ambient display)
+ when(mStatusBarStateController.isDozing()).thenReturn(true);
+
+ // THEN don't filter out the notification
+ assertFalse(mRankingFilter.shouldFilterOut(mEntry, 0));
+
+ // WHEN it's not dozing (showing the notification list)
+ when(mStatusBarStateController.isDozing()).thenReturn(false);
+
+ // THEN filter out the notification
+ assertTrue(mRankingFilter.shouldFilterOut(mEntry, 0));
+ }
+
+ private RankingBuilder getRankingForUnfilteredNotif() {
+ return new RankingBuilder()
+ .setKey(mEntry.getKey())
+ .setSuppressedVisualEffects(0)
+ .setSuspended(false);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
index 4451fa416912..5907a0a683a8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
@@ -21,6 +21,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
@@ -76,6 +77,8 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
@Mock
private StatusBar mStatusBar;
@Mock
+ private ShadeController mShadeController;
+ @Mock
private KeyguardStateController mKeyguardStateController;
@Mock
private Handler mHandler;
@@ -98,13 +101,12 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
when(mKeyguardBypassController.canPlaySubtleWindowAnimations()).thenReturn(true);
mContext.addMockSystemService(PowerManager.class, mPowerManager);
mDependency.injectTestDependency(NotificationMediaManager.class, mMediaManager);
- mDependency.injectTestDependency(StatusBarWindowController.class,
- mStatusBarWindowController);
res.addOverride(com.android.internal.R.integer.config_wakeUpDelayDoze, 0);
mBiometricUnlockController = new BiometricUnlockController(mContext, mDozeScrimController,
- mKeyguardViewMediator, mScrimController, mStatusBar, mKeyguardStateController,
- mHandler, mUpdateMonitor, res.getResources(), mKeyguardBypassController,
- mDozeParameters, mMetricsLogger, mDumpController);
+ mKeyguardViewMediator, mScrimController, mStatusBar, mShadeController,
+ mStatusBarWindowController, mKeyguardStateController, mHandler, mUpdateMonitor,
+ res.getResources(), mKeyguardBypassController, mDozeParameters, mMetricsLogger,
+ mDumpController);
mBiometricUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
}
@@ -113,7 +115,8 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
BiometricSourceType.FINGERPRINT);
verify(mStatusBarKeyguardViewManager).showBouncer(eq(false));
- verify(mStatusBarKeyguardViewManager).animateCollapsePanels(anyFloat());
+ verify(mShadeController).animateCollapsePanels(anyInt(), anyBoolean(), anyBoolean(),
+ anyFloat());
}
@Test
@@ -136,7 +139,8 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
BiometricSourceType.FINGERPRINT);
verify(mStatusBarKeyguardViewManager, never()).showBouncer(anyBoolean());
- verify(mStatusBarKeyguardViewManager).animateCollapsePanels(anyFloat());
+ verify(mShadeController).animateCollapsePanels(anyInt(), anyBoolean(), anyBoolean(),
+ anyFloat());
}
@Test
@@ -155,7 +159,8 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
BiometricSourceType.FACE);
- verify(mStatusBarKeyguardViewManager, never()).animateCollapsePanels(anyFloat());
+ verify(mShadeController, never()).animateCollapsePanels(anyInt(), anyBoolean(),
+ anyBoolean(), anyFloat());
verify(mStatusBarKeyguardViewManager, never()).notifyKeyguardAuthenticated(anyBoolean());
}
@@ -168,7 +173,8 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
BiometricSourceType.FACE);
- verify(mStatusBarKeyguardViewManager, never()).animateCollapsePanels(anyFloat());
+ verify(mShadeController, never()).animateCollapsePanels(anyInt(), anyBoolean(),
+ anyBoolean(), anyFloat());
verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(eq(false));
}
@@ -201,7 +207,8 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
BiometricSourceType.FACE);
verify(mStatusBarKeyguardViewManager, never()).showBouncer(anyBoolean());
- verify(mStatusBarKeyguardViewManager, never()).animateCollapsePanels(anyFloat());
+ verify(mShadeController, never()).animateCollapsePanels(anyInt(), anyBoolean(),
+ anyBoolean(), anyFloat());
assertThat(mBiometricUnlockController.getMode())
.isEqualTo(BiometricUnlockController.MODE_NONE);
}
@@ -253,7 +260,8 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
BiometricSourceType.FACE);
- verify(mStatusBarKeyguardViewManager, never()).animateCollapsePanels(anyFloat());
+ verify(mShadeController, never()).animateCollapsePanels(anyInt(), anyBoolean(),
+ anyBoolean(), anyFloat());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
index 0df2ebc8adfd..39afbe0a1a23 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
@@ -254,6 +254,7 @@ public class NavigationBarFragmentTest extends SysuiBaseFragmentTest {
mDivider,
Optional.of(mRecents),
() -> mock(StatusBar.class),
+ mock(ShadeController.class),
mHandler);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index d7c00cf3038d..532192ba97ae 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -111,6 +111,8 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
private Handler mHandler;
@Mock
private BubbleController mBubbleController;
+ @Mock
+ private ShadeControllerImpl mShadeController;
@Mock
private ActivityIntentHelper mActivityIntentHelper;
@@ -177,7 +179,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
mKeyguardStateController,
mock(NotificationInterruptionStateProvider.class), mock(MetricsLogger.class),
mock(LockPatternUtils.class), mHandler, mHandler, mActivityIntentHelper,
- mBubbleController, mSuperStatusBarViewFactory))
+ mBubbleController, mShadeController, mSuperStatusBarViewFactory))
.setStatusBar(mStatusBar)
.setNotificationPresenter(mock(NotificationPresenter.class))
.setActivityLaunchAnimator(mock(ActivityLaunchAnimator.class))
@@ -194,7 +196,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
// set up addPostCollapseAction to synchronously invoke the Runnable arg
doAnswer(answerVoid(Runnable::run))
- .when(mStatusBar).addPostCollapseAction(any(Runnable.class));
+ .when(mShadeController).addPostCollapseAction(any(Runnable.class));
// set up Handler to synchronously invoke the Runnable arg
doAnswer(answerVoid(Runnable::run))
@@ -219,7 +221,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
mNotificationActivityStarter.onNotificationClicked(sbn, mNotificationRow);
// Then
- verify(mStatusBar, atLeastOnce()).collapsePanel();
+ verify(mShadeController, atLeastOnce()).collapsePanel();
verify(mContentIntent).sendAndReturnResult(
any(Context.class),
@@ -254,7 +256,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
verify(mBubbleController).expandStackAndSelectBubble(eq(sbn.getKey()));
// This is called regardless, and simply short circuits when there is nothing to do.
- verify(mStatusBar, atLeastOnce()).collapsePanel();
+ verify(mShadeController, atLeastOnce()).collapsePanel();
verify(mAssistManager).hideAssist();
@@ -284,7 +286,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
// Then
verify(mBubbleController).expandStackAndSelectBubble(eq(sbn.getKey()));
- verify(mStatusBar, atLeastOnce()).collapsePanel();
+ verify(mShadeController, atLeastOnce()).collapsePanel();
verify(mAssistManager).hideAssist();
@@ -314,7 +316,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
// Then
verify(mBubbleController).expandStackAndSelectBubble(eq(sbn.getKey()));
- verify(mStatusBar, atLeastOnce()).collapsePanel();
+ verify(mShadeController, atLeastOnce()).collapsePanel();
verify(mAssistManager).hideAssist();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
index fb6e1684c376..575f145bcc63 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
@@ -115,7 +115,7 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase {
mock(NotificationAlertingManager.class),
mock(NotificationRowBinderImpl.class), mock(KeyguardStateController.class),
mock(KeyguardIndicationController.class),
- mStatusBar, mCommandQueue);
+ mStatusBar, mock(ShadeControllerImpl.class), mCommandQueue);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
index 6dfd0828de9a..cd2c3498ce56 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
@@ -73,7 +73,7 @@ public class StatusBarRemoteInputCallbackTest extends SysuiTestCase {
mRemoteInputCallback = spy(new StatusBarRemoteInputCallback(mContext,
mock(NotificationGroupManager.class), mNotificationLockscreenUserManager,
mKeyguardStateController, mStatusBarStateController, mStatusBarKeyguardViewManager,
- mActivityStarter, () -> mShadeController, new CommandQueue(mContext)));
+ mActivityStarter, mShadeController, new CommandQueue(mContext)));
mRemoteInputCallback.mChallengeReceiver = mRemoteInputCallback.new ChallengeReceiver();
}
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 be6809732963..d3fce567714d 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
@@ -63,6 +63,7 @@ import android.util.DisplayMetrics;
import android.util.SparseArray;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
+import android.view.WindowManager;
import android.widget.LinearLayout;
import androidx.test.filters.SmallTest;
@@ -243,6 +244,7 @@ public class StatusBarTest extends SysuiTestCase {
@Mock private LockscreenLockIconController mLockscreenLockIconController;
@Mock private StatusBarNotificationActivityStarter.Builder
mStatusBarNotificationActivityStarterBuilder;
+ private ShadeController mShadeController;
@Before
public void setup() throws Exception {
@@ -310,6 +312,11 @@ public class StatusBarTest extends SysuiTestCase {
when(mStatusBarComponent.getStatusBarWindowViewController()).thenReturn(
mStatusBarWindowViewController);
+ mShadeController = new ShadeControllerImpl(mCommandQueue,
+ mStatusBarStateController, mStatusBarWindowController,
+ mStatusBarKeyguardViewManager, mContext.getSystemService(WindowManager.class),
+ () -> mStatusBar, () -> mAssistManager, () -> mBubbleController);
+
mStatusBar = new StatusBar(
mContext,
mFeatureFlags,
@@ -382,6 +389,7 @@ public class StatusBarTest extends SysuiTestCase {
Optional.of(mDivider),
mLightsOutNotifController,
mStatusBarNotificationActivityStarterBuilder,
+ mShadeController,
mSuperStatusBarViewFactory,
mStatusBarKeyguardViewManager,
mViewMediatorCallback,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java
index 00ea18749de3..9f899ee117e9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java
@@ -102,7 +102,7 @@ public class StatusBarWindowViewTest extends SysuiTestCase {
mDozeLog,
mDozeParameters,
new CommandQueue(mContext),
- () -> mShadeController,
+ mShadeController,
mDockManager,
mView);
mController.setupExpandedStatusBar();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/DeviceConfigProxyFake.java b/packages/SystemUI/tests/src/com/android/systemui/util/DeviceConfigProxyFake.java
index 426aba03d5d8..260ff2dafeed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/DeviceConfigProxyFake.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/DeviceConfigProxyFake.java
@@ -69,8 +69,11 @@ public class DeviceConfigProxyFake extends DeviceConfigProxy {
}
for (Pair<Executor, OnPropertiesChangedListener> listener : mListeners) {
- listener.first.execute(() -> listener.second.onPropertiesChanged(
- new Properties(namespace, mProperties.get(namespace))));
+ Properties.Builder propBuilder = new Properties.Builder(namespace);
+ for (String key : mProperties.get(namespace).keySet()) {
+ propBuilder.setString(key, mProperties.get(namespace).get(key));
+ }
+ listener.first.execute(() -> listener.second.onPropertiesChanged(propBuilder.build()));
}
return true;
}
@@ -88,10 +91,12 @@ public class DeviceConfigProxyFake extends DeviceConfigProxy {
private Properties propsForNamespaceAndName(String namespace, String name) {
if (mProperties.containsKey(namespace) && mProperties.get(namespace).containsKey(name)) {
- return new Properties(namespace, mProperties.get(namespace));
+ return new Properties.Builder(namespace)
+ .setString(name, mProperties.get(namespace).get(name)).build();
}
if (mDefaultProperties.containsKey(namespace)) {
- return new Properties(namespace, mDefaultProperties.get(namespace));
+ return new Properties.Builder(namespace)
+ .setString(name, mDefaultProperties.get(namespace).get(name)).build();
}
return null;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wm/DisplayLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/wm/DisplayLayoutTest.java
new file mode 100644
index 000000000000..9596a73eaf3e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/wm/DisplayLayoutTest.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2019 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.wm;
+
+import static android.content.res.Configuration.UI_MODE_TYPE_NORMAL;
+import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Insets;
+import android.graphics.Rect;
+import android.view.DisplayCutout;
+import android.view.DisplayInfo;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.R;
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Test;
+
+@SmallTest
+public class DisplayLayoutTest extends SysuiTestCase {
+
+ @Test
+ public void testInsets() {
+ Resources res = createResources(40, 50, false, 30, 40);
+ // Test empty display, no bars or anything
+ DisplayInfo info = createDisplayInfo(1000, 1500, 0, ROTATION_0);
+ DisplayLayout dl = new DisplayLayout(info, res, false, false);
+ assertEquals(new Rect(0, 0, 0, 0), dl.stableInsets());
+ assertEquals(new Rect(0, 0, 0, 0), dl.nonDecorInsets());
+
+ // Test with bars
+ dl = new DisplayLayout(info, res, true, true);
+ assertEquals(new Rect(0, 40, 0, 50), dl.stableInsets());
+ assertEquals(new Rect(0, 0, 0, 50), dl.nonDecorInsets());
+
+ // Test just cutout
+ info = createDisplayInfo(1000, 1500, 60, ROTATION_0);
+ dl = new DisplayLayout(info, res, false, false);
+ assertEquals(new Rect(0, 60, 0, 0), dl.stableInsets());
+ assertEquals(new Rect(0, 60, 0, 0), dl.nonDecorInsets());
+
+ // Test with bars and cutout
+ dl = new DisplayLayout(info, res, true, true);
+ assertEquals(new Rect(0, 60, 0, 50), dl.stableInsets());
+ assertEquals(new Rect(0, 60, 0, 50), dl.nonDecorInsets());
+ }
+
+ @Test
+ public void testRotate() {
+ // Basic rotate utility
+ Rect testParent = new Rect(0, 0, 1000, 600);
+ Rect testInner = new Rect(40, 20, 120, 80);
+ Rect testResult = new Rect(testInner);
+ DisplayLayout.rotateBounds(testResult, testParent, 1);
+ assertEquals(new Rect(20, 880, 80, 960), testResult);
+ testResult.set(testInner);
+ DisplayLayout.rotateBounds(testResult, testParent, 2);
+ assertEquals(new Rect(880, 20, 960, 80), testResult);
+ testResult.set(testInner);
+ DisplayLayout.rotateBounds(testResult, testParent, 3);
+ assertEquals(new Rect(520, 40, 580, 120), testResult);
+
+ Resources res = createResources(40, 50, false, 30, 40);
+ DisplayInfo info = createDisplayInfo(1000, 1500, 60, ROTATION_0);
+ DisplayLayout dl = new DisplayLayout(info, res, true, true);
+ assertEquals(new Rect(0, 60, 0, 50), dl.stableInsets());
+ assertEquals(new Rect(0, 60, 0, 50), dl.nonDecorInsets());
+
+ // Rotate to 90
+ dl.rotateTo(res, ROTATION_90);
+ assertEquals(new Rect(60, 30, 0, 40), dl.stableInsets());
+ assertEquals(new Rect(60, 0, 0, 40), dl.nonDecorInsets());
+
+ // Rotate with moving navbar
+ res = createResources(40, 50, true, 30, 40);
+ dl = new DisplayLayout(info, res, true, true);
+ dl.rotateTo(res, ROTATION_270);
+ assertEquals(new Rect(40, 30, 60, 0), dl.stableInsets());
+ assertEquals(new Rect(40, 0, 60, 0), dl.nonDecorInsets());
+ }
+
+ private Resources createResources(
+ int navLand, int navPort, boolean navMoves, int statusLand, int statusPort) {
+ Configuration cfg = new Configuration();
+ cfg.uiMode = UI_MODE_TYPE_NORMAL;
+ Resources res = mock(Resources.class);
+ doReturn(navLand).when(res).getDimensionPixelSize(
+ R.dimen.navigation_bar_height_landscape_car_mode);
+ doReturn(navPort).when(res).getDimensionPixelSize(R.dimen.navigation_bar_height_car_mode);
+ doReturn(navLand).when(res).getDimensionPixelSize(R.dimen.navigation_bar_width_car_mode);
+ doReturn(navLand).when(res).getDimensionPixelSize(R.dimen.navigation_bar_height_landscape);
+ doReturn(navPort).when(res).getDimensionPixelSize(R.dimen.navigation_bar_height);
+ doReturn(navLand).when(res).getDimensionPixelSize(R.dimen.navigation_bar_width);
+ doReturn(navMoves).when(res).getBoolean(R.bool.config_navBarCanMove);
+ doReturn(statusLand).when(res).getDimensionPixelSize(R.dimen.status_bar_height_landscape);
+ doReturn(statusPort).when(res).getDimensionPixelSize(R.dimen.status_bar_height_portrait);
+ doReturn(cfg).when(res).getConfiguration();
+ return res;
+ }
+
+ private DisplayInfo createDisplayInfo(int width, int height, int cutoutHeight, int rotation) {
+ DisplayInfo info = new DisplayInfo();
+ info.logicalWidth = width;
+ info.logicalHeight = height;
+ info.rotation = rotation;
+ if (cutoutHeight > 0) {
+ info.displayCutout = new DisplayCutout(
+ Insets.of(0, cutoutHeight, 0, 0) /* safeInsets */, null /* boundLeft */,
+ new Rect(width / 2 - cutoutHeight, 0, width / 2 + cutoutHeight,
+ cutoutHeight) /* boundTop */, null /* boundRight */,
+ null /* boundBottom */);
+ } else {
+ info.displayCutout = DisplayCutout.NO_CUTOUT;
+ }
+ info.logicalDensityDpi = 300;
+ return info;
+ }
+}
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
index eb0d443f4bfc..7fb286b5fa11 100644
--- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
@@ -17,6 +17,7 @@ package android.net;
import static android.Manifest.permission.NETWORK_STACK;
import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
+import static android.net.ConnectivityManager.TETHER_ERROR_SERVICE_UNAVAIL;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -175,6 +176,10 @@ public class TetheringManager {
*/
@Deprecated
public int tether(@NonNull String iface) {
+ if (mConnector == null) {
+ Slog.wtf(TAG, "Tethering not ready yet");
+ return TETHER_ERROR_SERVICE_UNAVAIL;
+ }
try {
mConnector.tether(iface);
} catch (RemoteException e) {
@@ -191,6 +196,10 @@ public class TetheringManager {
*/
@Deprecated
public int untether(@NonNull String iface) {
+ if (mConnector == null) {
+ Slog.wtf(TAG, "Tethering not ready yet");
+ return TETHER_ERROR_SERVICE_UNAVAIL;
+ }
try {
mConnector.untether(iface);
} catch (RemoteException e) {
@@ -210,6 +219,10 @@ public class TetheringManager {
*/
@Deprecated
public int setUsbTethering(boolean enable) {
+ if (mConnector == null) {
+ Slog.wtf(TAG, "Tethering not ready yet");
+ return TETHER_ERROR_SERVICE_UNAVAIL;
+ }
try {
mConnector.setUsbTethering(enable);
} catch (RemoteException e) {
@@ -227,6 +240,10 @@ public class TetheringManager {
// TODO: improve the usage of ResultReceiver, b/145096122
public void startTethering(int type, @NonNull ResultReceiver receiver,
boolean showProvisioningUi) {
+ if (mConnector == null) {
+ Slog.wtf(TAG, "Tethering not ready yet");
+ return;
+ }
try {
mConnector.startTethering(type, receiver, showProvisioningUi);
} catch (RemoteException e) {
@@ -241,6 +258,10 @@ public class TetheringManager {
* {@hide}
*/
public void stopTethering(int type) {
+ if (mConnector == null) {
+ Slog.wtf(TAG, "Tethering not ready yet");
+ return;
+ }
try {
mConnector.stopTethering(type);
} catch (RemoteException e) {
@@ -258,6 +279,10 @@ public class TetheringManager {
// TODO: improve the usage of ResultReceiver, b/145096122
public void requestLatestTetheringEntitlementResult(int type, @NonNull ResultReceiver receiver,
boolean showEntitlementUi) {
+ if (mConnector == null) {
+ Slog.wtf(TAG, "Tethering not ready yet");
+ return;
+ }
try {
mConnector.requestLatestTetheringEntitlementResult(type, receiver, showEntitlementUi);
} catch (RemoteException e) {
diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
index 7e8edf212bdd..26bb7c35b9dc 100644
--- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
+++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
@@ -465,7 +465,7 @@ public final class AutoFillUI {
if (mCreateFillUiRunnable != null) {
if (sDebug) Slog.d(TAG, "start the pending fill UI request..");
- mCreateFillUiRunnable.run();
+ mHandler.post(mCreateFillUiRunnable);
mCreateFillUiRunnable = null;
}
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index f8f685d939a7..87b1bdfbe2ba 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -5573,7 +5573,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
* @param linkProperties the initial link properties of this network. They can be updated
* later : see {@link #updateLinkProperties}.
* @param networkCapabilities the initial capabilites of this network. They can be updated
- * later : see {@link #updateNetworkCapabilities}.
+ * later : see {@link #updateCapabilities}.
* @param currentScore the initial score of the network. See
* {@link NetworkAgentInfo#getCurrentScore}.
* @param networkMisc metadata about the network. This is never updated.
@@ -5864,6 +5864,19 @@ public class ConnectivityService extends IConnectivityManager.Stub
return INetd.PERMISSION_NONE;
}
+ private void updateNetworkPermissions(@NonNull final NetworkAgentInfo nai,
+ @NonNull final NetworkCapabilities newNc) {
+ final int oldPermission = getNetworkPermission(nai.networkCapabilities);
+ final int newPermission = getNetworkPermission(newNc);
+ if (oldPermission != newPermission && nai.created && !nai.isVPN()) {
+ try {
+ mNMS.setNetworkPermission(nai.network.netId, newPermission);
+ } catch (RemoteException e) {
+ loge("Exception in setNetworkPermission: " + e);
+ }
+ }
+ }
+
/**
* Augments the NetworkCapabilities passed in by a NetworkAgent with capabilities that are
* maintained here that the NetworkAgent is not aware of (e.g., validated, captive portal,
@@ -5935,21 +5948,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
* @param nai the network having its capabilities updated.
* @param nc the new network capabilities.
*/
- private void updateCapabilities(int oldScore, NetworkAgentInfo nai, NetworkCapabilities nc) {
+ private void updateCapabilities(final int oldScore, @NonNull final NetworkAgentInfo nai,
+ @NonNull final NetworkCapabilities nc) {
NetworkCapabilities newNc = mixInCapabilities(nai, nc);
-
if (Objects.equals(nai.networkCapabilities, newNc)) return;
-
- final int oldPermission = getNetworkPermission(nai.networkCapabilities);
- final int newPermission = getNetworkPermission(newNc);
- if (oldPermission != newPermission && nai.created && !nai.isVPN()) {
- try {
- mNMS.setNetworkPermission(nai.network.netId, newPermission);
- } catch (RemoteException e) {
- loge("Exception in setNetworkPermission: " + e);
- }
- }
-
+ updateNetworkPermissions(nai, nc);
final NetworkCapabilities prevNc = nai.getAndSetNetworkCapabilities(newNc);
updateUids(nai, prevNc, newNc);
@@ -6296,6 +6299,52 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
+ // An accumulator class to gather the list of changes that result from a rematch.
+ // TODO : enrich to represent an entire set of changes to apply.
+ private static class NetworkReassignment {
+ static class NetworkBgStatePair {
+ @NonNull final NetworkAgentInfo mNetwork;
+ final boolean mOldBackground;
+ NetworkBgStatePair(@NonNull final NetworkAgentInfo network,
+ final boolean oldBackground) {
+ mNetwork = network;
+ mOldBackground = oldBackground;
+ }
+ }
+
+ static class RequestReassignment {
+ @NonNull public final NetworkRequestInfo mRequest;
+ @Nullable public final NetworkAgentInfo mOldNetwork;
+ @Nullable public final NetworkAgentInfo mNewNetwork;
+ RequestReassignment(@NonNull final NetworkRequestInfo request,
+ @Nullable final NetworkAgentInfo oldNetwork,
+ @Nullable final NetworkAgentInfo newNetwork) {
+ mRequest = request;
+ mOldNetwork = oldNetwork;
+ mNewNetwork = newNetwork;
+ }
+ }
+
+ @NonNull private final Set<NetworkBgStatePair> mRematchedNetworks = new ArraySet<>();
+ @NonNull private final List<RequestReassignment> mReassignments = new ArrayList<>();
+
+ @NonNull Iterable<NetworkBgStatePair> getRematchedNetworks() {
+ return mRematchedNetworks;
+ }
+
+ @NonNull Iterable<RequestReassignment> getRequestReassignments() {
+ return mReassignments;
+ }
+
+ void addRequestReassignment(@NonNull final RequestReassignment reassignment) {
+ mReassignments.add(reassignment);
+ }
+
+ void addRematchedNetwork(@NonNull final NetworkBgStatePair network) {
+ mRematchedNetworks.add(network);
+ }
+ }
+
private ArrayMap<NetworkRequestInfo, NetworkAgentInfo> computeRequestReassignmentForNetwork(
@NonNull final NetworkAgentInfo newNetwork) {
final int score = newNetwork.getCurrentScore();
@@ -6341,8 +6390,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
// needed. A network is needed if it is the best network for
// one or more NetworkRequests, or if it is a VPN.
//
- // - Tears down newNetwork if it just became validated
- // but turns out to be unneeded.
+ // - Writes into the passed reassignment object all changes that should be done for
+ // rematching this network with all requests, to be applied later.
//
// NOTE: This function only adds NetworkRequests that "newNetwork" could satisfy,
// it does not remove NetworkRequests that other Networks could better satisfy.
@@ -6350,29 +6399,29 @@ public class ConnectivityService extends IConnectivityManager.Stub
// This function should be used when possible instead of {@code rematchAllNetworksAndRequests}
// as it performs better by a factor of the number of Networks.
//
+ // TODO : stop writing to the passed reassignment. This is temporarily more useful, but
+ // it's unidiomatic Java and it's hard to read.
+ //
+ // @param changes a currently-building list of changes to write to
// @param newNetwork is the network to be matched against NetworkRequests.
// @param now the time the rematch starts, as returned by SystemClock.elapsedRealtime();
- private void rematchNetworkAndRequests(NetworkAgentInfo newNetwork, long now) {
+ private void rematchNetworkAndRequests(@NonNull final NetworkReassignment changes,
+ @NonNull final NetworkAgentInfo newNetwork, final long now) {
ensureRunningOnConnectivityServiceThread();
if (!newNetwork.everConnected) return;
boolean isNewDefault = false;
NetworkAgentInfo oldDefaultNetwork = null;
- final boolean wasBackgroundNetwork = newNetwork.isBackgroundNetwork();
- final int score = newNetwork.getCurrentScore();
+ changes.addRematchedNetwork(new NetworkReassignment.NetworkBgStatePair(newNetwork,
+ newNetwork.isBackgroundNetwork()));
if (VDBG || DDBG) log("rematching " + newNetwork.name());
final ArrayMap<NetworkRequestInfo, NetworkAgentInfo> reassignedRequests =
computeRequestReassignmentForNetwork(newNetwork);
- NetworkCapabilities nc = newNetwork.networkCapabilities;
- if (VDBG) log(" network has: " + nc);
-
// Find and migrate to this Network any NetworkRequests for
// which this network is now the best.
- final ArrayList<NetworkAgentInfo> removedRequests = new ArrayList<>();
- final ArrayList<NetworkRequestInfo> addedRequests = new ArrayList<>();
for (final Map.Entry<NetworkRequestInfo, NetworkAgentInfo> entry :
reassignedRequests.entrySet()) {
final NetworkRequestInfo nri = entry.getKey();
@@ -6386,7 +6435,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
previousSatisfier.removeRequest(nri.request.requestId);
previousSatisfier.lingerRequest(nri.request, now, mLingerDelayMs);
- removedRequests.add(previousSatisfier);
} else {
if (VDBG || DDBG) log(" accepting network in place of null");
}
@@ -6395,7 +6443,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (!newSatisfier.addRequest(nri.request)) {
Slog.wtf(TAG, "BUG: " + newSatisfier.name() + " already has " + nri.request);
}
- addedRequests.add(nri);
+ changes.addRequestReassignment(new NetworkReassignment.RequestReassignment(
+ nri, previousSatisfier, newSatisfier));
// Tell NetworkFactories about the new score, so they can stop
// trying to connect if they know they cannot match it.
// TODO - this could get expensive if we have a lot of requests for this
@@ -6452,48 +6501,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
// Have a new default network, release the transition wakelock in
scheduleReleaseNetworkTransitionWakelock();
}
-
- if (!newNetwork.networkCapabilities.equalRequestableCapabilities(nc)) {
- Slog.wtf(TAG, String.format(
- "BUG: %s changed requestable capabilities during rematch: %s -> %s",
- newNetwork.name(), nc, newNetwork.networkCapabilities));
- }
- if (newNetwork.getCurrentScore() != score) {
- Slog.wtf(TAG, String.format(
- "BUG: %s changed score during rematch: %d -> %d",
- newNetwork.name(), score, newNetwork.getCurrentScore()));
- }
-
- // Notify requested networks are available after the default net is switched, but
- // before LegacyTypeTracker sends legacy broadcasts
- for (NetworkRequestInfo nri : addedRequests) notifyNetworkAvailable(newNetwork, nri);
-
- // Finally, process listen requests and update capabilities if the background state has
- // changed for this network. For consistency with previous behavior, send onLost callbacks
- // before onAvailable.
- processNewlyLostListenRequests(newNetwork);
-
- // Maybe the network changed background states. Update its capabilities.
- final boolean backgroundChanged = wasBackgroundNetwork != newNetwork.isBackgroundNetwork();
- if (backgroundChanged) {
- final NetworkCapabilities newNc = mixInCapabilities(newNetwork,
- newNetwork.networkCapabilities);
-
- final int oldPermission = getNetworkPermission(newNetwork.networkCapabilities);
- final int newPermission = getNetworkPermission(newNc);
- if (oldPermission != newPermission) {
- try {
- mNMS.setNetworkPermission(newNetwork.network.netId, newPermission);
- } catch (RemoteException e) {
- loge("Exception in setNetworkPermission: " + e);
- }
- }
-
- newNetwork.getAndSetNetworkCapabilities(newNc);
- notifyNetworkCallbacks(newNetwork, ConnectivityManager.CALLBACK_CAP_CHANGED);
- }
-
- processNewlySatisfiedListenRequests(newNetwork);
}
/**
@@ -6515,12 +6522,33 @@ public class ConnectivityService extends IConnectivityManager.Stub
// scoring network and then a higher scoring network, which could produce multiple
// callbacks.
Arrays.sort(nais);
+ final NetworkReassignment changes = new NetworkReassignment();
for (final NetworkAgentInfo nai : nais) {
- rematchNetworkAndRequests(nai, now);
+ rematchNetworkAndRequests(changes, nai, now);
}
final NetworkAgentInfo newDefaultNetwork = getDefaultNetwork();
+ // Notify requested networks are available after the default net is switched, but
+ // before LegacyTypeTracker sends legacy broadcasts
+ for (final NetworkReassignment.RequestReassignment event :
+ changes.getRequestReassignments()) {
+ if (null != event.mNewNetwork) {
+ notifyNetworkAvailable(event.mNewNetwork, event.mRequest);
+ }
+ }
+
+ for (final NetworkReassignment.NetworkBgStatePair event : changes.getRematchedNetworks()) {
+ // Process listen requests and update capabilities if the background state has
+ // changed for this network. For consistency with previous behavior, send onLost
+ // callbacks before onAvailable.
+ processNewlyLostListenRequests(event.mNetwork);
+ if (event.mOldBackground != event.mNetwork.isBackgroundNetwork()) {
+ applyBackgroundChangeForRematch(event.mNetwork);
+ }
+ processNewlySatisfiedListenRequests(event.mNetwork);
+ }
+
for (final NetworkAgentInfo nai : nais) {
// Rematching may have altered the linger state of some networks, so update all linger
// timers. updateLingerState reads the state from the network agent and does nothing
@@ -6552,6 +6580,24 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
+ /**
+ * Apply a change in background state resulting from rematching networks with requests.
+ *
+ * During rematch, a network may change background states by starting to satisfy or stopping
+ * to satisfy a foreground request. Listens don't count for this. When a network changes
+ * background states, its capabilities need to be updated and callbacks fired for the
+ * capability change.
+ *
+ * @param nai The network that changed background states
+ */
+ private void applyBackgroundChangeForRematch(@NonNull final NetworkAgentInfo nai) {
+ final NetworkCapabilities newNc = mixInCapabilities(nai, nai.networkCapabilities);
+ if (Objects.equals(nai.networkCapabilities, newNc)) return;
+ updateNetworkPermissions(nai, newNc);
+ nai.getAndSetNetworkCapabilities(newNc);
+ notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
+ }
+
private void updateLegacyTypeTrackerAndVpnLockdownForRematch(
@Nullable final NetworkAgentInfo oldDefaultNetwork,
@Nullable final NetworkAgentInfo newDefaultNetwork,
diff --git a/services/core/java/com/android/server/GnssManagerService.java b/services/core/java/com/android/server/GnssManagerService.java
index cbf2a622fd2e..bbcfdc63f3f1 100644
--- a/services/core/java/com/android/server/GnssManagerService.java
+++ b/services/core/java/com/android/server/GnssManagerService.java
@@ -56,6 +56,7 @@ import com.android.server.location.GnssMeasurementCorrectionsProvider;
import com.android.server.location.GnssMeasurementsProvider;
import com.android.server.location.GnssNavigationMessageProvider;
import com.android.server.location.GnssStatusListenerHelper;
+import com.android.server.location.LocationUsageLogger;
import com.android.server.location.RemoteListenerHelper;
import java.io.FileDescriptor;
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 6300ab878d49..cad917b073a5 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -104,6 +104,7 @@ import com.android.server.location.LocationRequestStatistics;
import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
import com.android.server.location.LocationRequestStatistics.PackageStatistics;
import com.android.server.location.LocationSettingsStore;
+import com.android.server.location.LocationUsageLogger;
import com.android.server.location.MockProvider;
import com.android.server.location.PassiveProvider;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
@@ -158,21 +159,15 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- private static final String TAG = "LocationManagerService";
+ public static final String TAG = "LocationManagerService";
public static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
private static final String WAKELOCK_KEY = "*location*";
- // Location resolution level: no location data whatsoever
private static final int RESOLUTION_LEVEL_NONE = 0;
- // Location resolution level: coarse location data only
private static final int RESOLUTION_LEVEL_COARSE = 1;
- // Location resolution level: fine location data
private static final int RESOLUTION_LEVEL_FINE = 2;
- private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
- android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
-
private static final String NETWORK_LOCATION_SERVICE_ACTION =
"com.android.location.service.v3.NetworkLocationProvider";
private static final String FUSED_LOCATION_SERVICE_ACTION =
@@ -198,6 +193,8 @@ public class LocationManagerService extends ILocationManager.Stub {
private final Object mLock = new Object();
private final Context mContext;
private final Handler mHandler;
+ private final LocationSettingsStore mSettingsStore;
+ private final LocationUsageLogger mLocationUsageLogger;
private AppOpsManager mAppOps;
private PackageManager mPackageManager;
@@ -205,8 +202,6 @@ public class LocationManagerService extends ILocationManager.Stub {
private ActivityManager mActivityManager;
private UserManager mUserManager;
- private LocationSettingsStore mSettingsStore;
-
private GeofenceManager mGeofenceManager;
private LocationFudger mLocationFudger;
private GeocoderProxy mGeocodeProvider;
@@ -219,12 +214,12 @@ public class LocationManagerService extends ILocationManager.Stub {
// list of currently active providers
@GuardedBy("mLock")
- private final ArrayList<LocationProvider> mProviders = new ArrayList<>();
+ private final ArrayList<LocationProviderManager> mProviders = new ArrayList<>();
// list of non-mock providers, so that when mock providers replace real providers, they can be
// later re-replaced
@GuardedBy("mLock")
- private final ArrayList<LocationProvider> mRealProviders = new ArrayList<>();
+ private final ArrayList<LocationProviderManager> mRealProviders = new ArrayList<>();
@GuardedBy("mLock")
private final HashMap<Object, Receiver> mReceivers = new HashMap<>();
@@ -251,12 +246,10 @@ public class LocationManagerService extends ILocationManager.Stub {
@PowerManager.LocationPowerSaveMode
private int mBatterySaverMode;
- @GuardedBy("mLock")
- private final LocationUsageLogger mLocationUsageLogger;
-
private LocationManagerService(Context context) {
mContext = context;
mHandler = FgThread.getHandler();
+ mSettingsStore = new LocationSettingsStore(mContext, mHandler);
mLocationUsageLogger = new LocationUsageLogger();
// Let the package manager query which are the default location
@@ -274,6 +267,8 @@ public class LocationManagerService extends ILocationManager.Stub {
}
private void onSystemReady() {
+ mSettingsStore.onSystemReady();
+
synchronized (mLock) {
mPackageManager = mContext.getPackageManager();
mAppOps = mContext.getSystemService(AppOpsManager.class);
@@ -281,7 +276,6 @@ public class LocationManagerService extends ILocationManager.Stub {
mActivityManager = mContext.getSystemService(ActivityManager.class);
mUserManager = mContext.getSystemService(UserManager.class);
- mSettingsStore = new LocationSettingsStore(mContext, mHandler);
mLocationFudger = new LocationFudger(mContext, mHandler);
mGeofenceManager = new GeofenceManager(mContext, mSettingsStore);
@@ -421,14 +415,14 @@ public class LocationManagerService extends ILocationManager.Stub {
for (Receiver receiver : mReceivers.values()) {
receiver.updateMonitoring(true);
}
- for (LocationProvider p : mProviders) {
+ for (LocationProviderManager p : mProviders) {
applyRequirementsLocked(p);
}
}
@GuardedBy("mLock")
private void onPermissionsChangedLocked() {
- for (LocationProvider p : mProviders) {
+ for (LocationProviderManager p : mProviders) {
applyRequirementsLocked(p);
}
}
@@ -448,7 +442,7 @@ public class LocationManagerService extends ILocationManager.Stub {
mBatterySaverMode = newLocationMode;
- for (LocationProvider p : mProviders) {
+ for (LocationProviderManager p : mProviders) {
applyRequirementsLocked(p);
}
}
@@ -456,7 +450,7 @@ public class LocationManagerService extends ILocationManager.Stub {
@GuardedBy("mLock")
private void onScreenStateChangedLocked() {
if (mBatterySaverMode == PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF) {
- for (LocationProvider p : mProviders) {
+ for (LocationProviderManager p : mProviders) {
applyRequirementsLocked(p);
}
}
@@ -472,7 +466,7 @@ public class LocationManagerService extends ILocationManager.Stub {
intent.putExtra(LocationManager.EXTRA_LOCATION_ENABLED, isLocationEnabledForUser(userId));
mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
- for (LocationProvider p : mProviders) {
+ for (LocationProviderManager p : mProviders) {
p.onUseableChangedLocked(userId);
}
}
@@ -527,21 +521,21 @@ public class LocationManagerService extends ILocationManager.Stub {
@GuardedBy("mLock")
private void onBackgroundThrottleIntervalChangedLocked() {
- for (LocationProvider provider : mProviders) {
+ for (LocationProviderManager provider : mProviders) {
applyRequirementsLocked(provider);
}
}
@GuardedBy("mLock")
private void onBackgroundThrottleWhitelistChangedLocked() {
- for (LocationProvider p : mProviders) {
+ for (LocationProviderManager p : mProviders) {
applyRequirementsLocked(p);
}
}
@GuardedBy("lock")
private void onIgnoreSettingsWhitelistChangedLocked() {
- for (LocationProvider p : mProviders) {
+ for (LocationProviderManager p : mProviders) {
applyRequirementsLocked(p);
}
}
@@ -630,14 +624,15 @@ public class LocationManagerService extends ILocationManager.Stub {
@GuardedBy("mLock")
private void initializeProvidersLocked() {
// create a passive location provider, which is always enabled
- LocationProvider passiveProviderManager = new LocationProvider(PASSIVE_PROVIDER);
+ LocationProviderManager passiveProviderManager = new LocationProviderManager(
+ PASSIVE_PROVIDER);
addProviderLocked(passiveProviderManager);
mPassiveProvider = new PassiveProvider(mContext, passiveProviderManager);
passiveProviderManager.attachLocked(mPassiveProvider);
if (GnssManagerService.isGnssSupported()) {
// Create a gps location provider manager
- LocationProvider gnssProviderManager = new LocationProvider(GPS_PROVIDER);
+ LocationProviderManager gnssProviderManager = new LocationProviderManager(GPS_PROVIDER);
mRealProviders.add(gnssProviderManager);
addProviderLocked(gnssProviderManager);
@@ -668,7 +663,8 @@ public class LocationManagerService extends ILocationManager.Stub {
ensureFallbackFusedProviderPresentLocked(pkgs);
// bind to network provider
- LocationProvider networkProviderManager = new LocationProvider(NETWORK_PROVIDER);
+ LocationProviderManager networkProviderManager = new LocationProviderManager(
+ NETWORK_PROVIDER);
LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
mContext,
networkProviderManager,
@@ -685,7 +681,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
// bind to fused provider
- LocationProvider fusedProviderManager = new LocationProvider(FUSED_PROVIDER);
+ LocationProviderManager fusedProviderManager = new LocationProviderManager(FUSED_PROVIDER);
LocationProviderProxy fusedProvider = LocationProviderProxy.createAndBind(
mContext,
fusedProviderManager,
@@ -758,7 +754,7 @@ public class LocationManagerService extends ILocationManager.Stub {
Boolean.parseBoolean(fragments[7]) /* supportsBearing */,
Integer.parseInt(fragments[8]) /* powerRequirement */,
Integer.parseInt(fragments[9]) /* accuracy */);
- LocationProvider testProviderManager = new LocationProvider(name);
+ LocationProviderManager testProviderManager = new LocationProviderManager(name);
addProviderLocked(testProviderManager);
testProviderManager.attachLocked(
new MockProvider(mContext, testProviderManager, properties));
@@ -780,7 +776,7 @@ public class LocationManagerService extends ILocationManager.Stub {
onUserProfilesChangedLocked();
// let providers know the current user has changed
- for (LocationProvider p : mProviders) {
+ for (LocationProviderManager p : mProviders) {
p.onUseableChangedLocked(oldUserId);
p.onUseableChangedLocked(mCurrentUserId);
}
@@ -789,7 +785,7 @@ public class LocationManagerService extends ILocationManager.Stub {
/**
* Location provider manager, manages a LocationProvider.
*/
- class LocationProvider implements AbstractLocationProvider.LocationProviderManager {
+ class LocationProviderManager implements AbstractLocationProvider.LocationProviderManager {
private final String mName;
@@ -807,7 +803,7 @@ public class LocationManagerService extends ILocationManager.Stub {
@Nullable
private ProviderProperties mProperties;
- private LocationProvider(String name) {
+ private LocationProviderManager(String name) {
mName = name;
mProvider = null;
@@ -944,7 +940,7 @@ public class LocationManagerService extends ILocationManager.Stub {
return;
}
synchronized (mLock) {
- LocationProvider gpsProvider = getLocationProviderLocked(GPS_PROVIDER);
+ LocationProviderManager gpsProvider = getLocationProviderLocked(GPS_PROVIDER);
if (gpsProvider == null || !gpsProvider.isUseableLocked()) {
Slog.w(TAG, "reportLocationBatch() called without user permission");
return;
@@ -1035,7 +1031,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- private class MockLocationProvider extends LocationProvider {
+ private class MockLocationProvider extends LocationProviderManager {
private ProviderRequest mCurrentRequest;
@@ -1185,7 +1181,8 @@ public class LocationManagerService extends ILocationManager.Stub {
// See if receiver has any enabled update records. Also note if any update records
// are high power (has a high power provider with an interval under a threshold).
for (UpdateRecord updateRecord : mUpdateRecords.values()) {
- LocationProvider provider = getLocationProviderLocked(updateRecord.mProvider);
+ LocationProviderManager provider = getLocationProviderLocked(
+ updateRecord.mProvider);
if (provider == null) {
continue;
}
@@ -1461,7 +1458,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
@GuardedBy("mLock")
- private void addProviderLocked(LocationProvider provider) {
+ private void addProviderLocked(LocationProviderManager provider) {
Preconditions.checkState(getLocationProviderLocked(provider.getName()) == null);
mProviders.add(provider);
@@ -1472,7 +1469,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
@GuardedBy("mLock")
- private void removeProviderLocked(LocationProvider provider) {
+ private void removeProviderLocked(LocationProviderManager provider) {
if (mProviders.remove(provider)) {
// it would be more correct to call this for all users, but we know this can only
// affect the current user since providers are disabled for non-current users
@@ -1482,8 +1479,8 @@ public class LocationManagerService extends ILocationManager.Stub {
@GuardedBy("mLock")
@Nullable
- private LocationProvider getLocationProviderLocked(String providerName) {
- for (LocationProvider provider : mProviders) {
+ private LocationProviderManager getLocationProviderLocked(String providerName) {
+ for (LocationProviderManager provider : mProviders) {
if (providerName.equals(provider.getName())) {
return provider;
}
@@ -1534,7 +1531,7 @@ public class LocationManagerService extends ILocationManager.Stub {
// network and fused providers are ok with COARSE or FINE
return RESOLUTION_LEVEL_COARSE;
} else {
- for (LocationProvider lp : mProviders) {
+ for (LocationProviderManager lp : mProviders) {
if (!lp.getName().equals(provider)) {
continue;
}
@@ -1634,7 +1631,7 @@ public class LocationManagerService extends ILocationManager.Stub {
public List<String> getAllProviders() {
synchronized (mLock) {
ArrayList<String> providers = new ArrayList<>(mProviders.size());
- for (LocationProvider provider : mProviders) {
+ for (LocationProviderManager provider : mProviders) {
String name = provider.getName();
if (FUSED_PROVIDER.equals(name)) {
continue;
@@ -1655,7 +1652,7 @@ public class LocationManagerService extends ILocationManager.Stub {
int allowedResolutionLevel = getCallerAllowedResolutionLevel();
synchronized (mLock) {
ArrayList<String> providers = new ArrayList<>(mProviders.size());
- for (LocationProvider provider : mProviders) {
+ for (LocationProviderManager provider : mProviders) {
String name = provider.getName();
if (FUSED_PROVIDER.equals(name)) {
continue;
@@ -1705,7 +1702,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
@GuardedBy("mLock")
- private void updateProviderUseableLocked(LocationProvider provider) {
+ private void updateProviderUseableLocked(LocationProviderManager provider) {
boolean useable = provider.isUseableLocked();
ArrayList<Receiver> deadReceivers = null;
@@ -1744,14 +1741,14 @@ public class LocationManagerService extends ILocationManager.Stub {
@GuardedBy("mLock")
private void applyRequirementsLocked(String providerName) {
- LocationProvider provider = getLocationProviderLocked(providerName);
+ LocationProviderManager provider = getLocationProviderLocked(providerName);
if (provider != null) {
applyRequirementsLocked(provider);
}
}
@GuardedBy("mLock")
- private void applyRequirementsLocked(LocationProvider provider) {
+ private void applyRequirementsLocked(LocationProviderManager provider) {
ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider.getName());
WorkSource worksource = new WorkSource();
ProviderRequest providerRequest = new ProviderRequest();
@@ -2201,7 +2198,7 @@ public class LocationManagerService extends ILocationManager.Stub {
throw new IllegalArgumentException("provider name must not be null");
}
- LocationProvider provider = getLocationProviderLocked(name);
+ LocationProviderManager provider = getLocationProviderLocked(name);
if (provider == null) {
throw new IllegalArgumentException("provider doesn't exist: " + name);
}
@@ -2323,7 +2320,7 @@ public class LocationManagerService extends ILocationManager.Stub {
// or use the fused provider
String name = request.getProvider();
if (name == null) name = LocationManager.FUSED_PROVIDER;
- LocationProvider provider = getLocationProviderLocked(name);
+ LocationProviderManager provider = getLocationProviderLocked(name);
if (provider == null) return null;
// only the current user or location providers may get location this way
@@ -2453,7 +2450,7 @@ public class LocationManagerService extends ILocationManager.Stub {
"Access Fine Location permission not granted to inject Location");
synchronized (mLock) {
- LocationProvider provider = getLocationProviderLocked(location.getProvider());
+ LocationProviderManager provider = getLocationProviderLocked(location.getProvider());
if (provider == null || !provider.isUseableLocked()) {
return false;
}
@@ -2624,6 +2621,10 @@ public class LocationManagerService extends ILocationManager.Stub {
// throw NullPointerException to remain compatible with previous implementation
throw new NullPointerException();
}
+
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS, null);
+
synchronized (mLock) {
checkResolutionLevelIsSufficientForProviderUseLocked(getCallerAllowedResolutionLevel(),
providerName);
@@ -2633,13 +2634,7 @@ public class LocationManagerService extends ILocationManager.Stub {
LocationStatsEnums.API_SEND_EXTRA_COMMAND,
providerName);
- // and check for ACCESS_LOCATION_EXTRA_COMMANDS
- if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
- != PERMISSION_GRANTED)) {
- throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
- }
-
- LocationProvider provider = getLocationProviderLocked(providerName);
+ LocationProviderManager provider = getLocationProviderLocked(providerName);
if (provider != null) {
provider.sendExtraCommand(command, extras);
}
@@ -2662,7 +2657,7 @@ public class LocationManagerService extends ILocationManager.Stub {
@Override
public ProviderProperties getProviderProperties(String providerName) {
synchronized (mLock) {
- LocationProvider provider = getLocationProviderLocked(providerName);
+ LocationProviderManager provider = getLocationProviderLocked(providerName);
if (provider == null) {
return null;
}
@@ -2675,7 +2670,7 @@ public class LocationManagerService extends ILocationManager.Stub {
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_DEVICE_CONFIG,
Manifest.permission.READ_DEVICE_CONFIG + " permission required");
synchronized (mLock) {
- for (LocationProvider provider : mProviders) {
+ for (LocationProviderManager provider : mProviders) {
if (provider.getPackagesLocked().contains(packageName)) {
return true;
}
@@ -2689,7 +2684,7 @@ public class LocationManagerService extends ILocationManager.Stub {
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_DEVICE_CONFIG,
Manifest.permission.READ_DEVICE_CONFIG + " permission required");
synchronized (mLock) {
- LocationProvider provider = getLocationProviderLocked(providerName);
+ LocationProviderManager provider = getLocationProviderLocked(providerName);
return provider == null ? Collections.emptyList() : provider.getPackagesLocked();
}
}
@@ -2758,7 +2753,7 @@ public class LocationManagerService extends ILocationManager.Stub {
if (FUSED_PROVIDER.equals(providerName)) return false;
synchronized (mLock) {
- LocationProvider provider = getLocationProviderLocked(providerName);
+ LocationProviderManager provider = getLocationProviderLocked(providerName);
return provider != null && provider.isUseableLocked(userId);
}
}
@@ -2797,7 +2792,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
@GuardedBy("mLock")
- private void handleLocationChangedLocked(Location location, LocationProvider provider) {
+ private void handleLocationChangedLocked(Location location, LocationProviderManager provider) {
if (!mProviders.contains(provider)) {
return;
}
@@ -3029,7 +3024,7 @@ public class LocationManagerService extends ILocationManager.Stub {
synchronized (mLock) {
long identity = Binder.clearCallingIdentity();
try {
- LocationProvider oldProvider = getLocationProviderLocked(name);
+ LocationProviderManager oldProvider = getLocationProviderLocked(name);
if (oldProvider != null) {
removeProviderLocked(oldProvider);
}
@@ -3053,7 +3048,7 @@ public class LocationManagerService extends ILocationManager.Stub {
synchronized (mLock) {
long identity = Binder.clearCallingIdentity();
try {
- LocationProvider testProvider = getLocationProviderLocked(name);
+ LocationProviderManager testProvider = getLocationProviderLocked(name);
if (testProvider == null || !testProvider.isMock()) {
return;
}
@@ -3061,8 +3056,8 @@ public class LocationManagerService extends ILocationManager.Stub {
removeProviderLocked(testProvider);
// reinstate real provider if available
- LocationProvider realProvider = null;
- for (LocationProvider provider : mRealProviders) {
+ LocationProviderManager realProvider = null;
+ for (LocationProviderManager provider : mRealProviders) {
if (name.equals(provider.getName())) {
realProvider = provider;
break;
@@ -3086,7 +3081,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
synchronized (mLock) {
- LocationProvider testProvider = getLocationProviderLocked(providerName);
+ LocationProviderManager testProvider = getLocationProviderLocked(providerName);
if (testProvider == null || !testProvider.isMock()) {
throw new IllegalArgumentException("Provider \"" + providerName + "\" unknown");
}
@@ -3110,7 +3105,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
synchronized (mLock) {
- LocationProvider testProvider = getLocationProviderLocked(providerName);
+ LocationProviderManager testProvider = getLocationProviderLocked(providerName);
if (testProvider == null || !testProvider.isMock()) {
throw new IllegalArgumentException("Provider \"" + providerName + "\" unknown");
}
@@ -3128,7 +3123,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
synchronized (mLock) {
- LocationProvider testProvider = getLocationProviderLocked(providerName);
+ LocationProviderManager testProvider = getLocationProviderLocked(providerName);
if (testProvider == null || !testProvider.isMock()) {
throw new IllegalArgumentException("Provider \"" + providerName + "\" unknown");
}
@@ -3237,7 +3232,7 @@ public class LocationManagerService extends ILocationManager.Stub {
ipw.println("Location Providers:");
ipw.increaseIndent();
- for (LocationProvider provider : mProviders) {
+ for (LocationProviderManager provider : mProviders) {
provider.dumpLocked(fd, ipw, args);
}
ipw.decreaseIndent();
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
index 15e6021d23cd..deff440aa0a6 100644
--- a/services/core/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -346,8 +346,9 @@ public class PackageWatchdog {
if (mAllObservers.isEmpty()) {
return;
}
-
- if (failureReason == FAILURE_REASON_NATIVE_CRASH) {
+ boolean requiresImmediateAction = (failureReason == FAILURE_REASON_NATIVE_CRASH
+ || failureReason == FAILURE_REASON_EXPLICIT_HEALTH_CHECK);
+ if (requiresImmediateAction) {
handleFailureImmediately(packages, failureReason);
} else {
for (int pIndex = 0; pIndex < packages.size(); pIndex++) {
@@ -384,8 +385,8 @@ public class PackageWatchdog {
}
/**
- * For native crashes, call directly into each observer to mitigate the error without going
- * through failure threshold logic.
+ * For native crashes or explicit health check failures, call directly into each observer to
+ * mitigate the error without going through failure threshold logic.
*/
private void handleFailureImmediately(List<VersionedPackage> packages,
@FailureReasons int failureReason) {
@@ -531,6 +532,17 @@ public class PackageWatchdog {
default boolean isPersistent() {
return false;
}
+
+ /**
+ * Returns {@code true} if this observer wishes to observe the given package, {@code false}
+ * otherwise
+ *
+ * <p> A persistent observer may choose to start observing certain failing packages, even if
+ * it has not explicitly asked to watch the package with {@link #startObservingHealth}.
+ */
+ default boolean mayObservePackage(String packageName) {
+ return false;
+ }
}
long getTriggerFailureCount() {
@@ -867,13 +879,8 @@ public class PackageWatchdog {
Slog.wtf(TAG, "NetworkStack failed but could not find its package");
return;
}
- // This is a severe failure and recovery should be attempted immediately.
- // TODO: have a better way to handle such failures.
final List<VersionedPackage> pkgList = Collections.singletonList(pkg);
- final long failureCount = getTriggerFailureCount();
- for (int i = 0; i < failureCount; i++) {
- onPackageFailure(pkgList, FAILURE_REASON_EXPLICIT_HEALTH_CHECK);
- }
+ onPackageFailure(pkgList, FAILURE_REASON_EXPLICIT_HEALTH_CHECK);
});
}
@@ -1020,6 +1027,11 @@ public class PackageWatchdog {
*/
@GuardedBy("mLock")
public boolean onPackageFailureLocked(String packageName) {
+ if (packages.get(packageName) == null && registeredObserver.isPersistent()
+ && registeredObserver.mayObservePackage(packageName)) {
+ packages.put(packageName, sPackageWatchdog.newMonitoredPackage(
+ packageName, DEFAULT_OBSERVING_DURATION_MS, false));
+ }
MonitoredPackage p = packages.get(packageName);
if (p != null) {
return p.onFailureLocked();
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 0a6473ab92d9..29d3a1d7e7f9 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -1584,10 +1584,8 @@ class StorageManagerService extends IStorageManager.Stub
// Snapshot feature flag used for this boot
SystemProperties.set(StorageManager.PROP_ISOLATED_STORAGE_SNAPSHOT, Boolean.toString(
SystemProperties.getBoolean(StorageManager.PROP_ISOLATED_STORAGE, true)));
- SystemProperties.set(StorageManager.PROP_FUSE_SNAPSHOT, Boolean.toString(
- SystemProperties.getBoolean(StorageManager.PROP_FUSE, false)));
- mIsFuseEnabled = SystemProperties.getBoolean(StorageManager.PROP_FUSE_SNAPSHOT, false);
+ mIsFuseEnabled = SystemProperties.getBoolean(StorageManager.PROP_FUSE, false);
mContext = context;
mResolver = mContext.getContentResolver();
mCallbacks = new Callbacks(FgThread.get().getLooper());
@@ -1647,12 +1645,22 @@ class StorageManagerService extends IStorageManager.Stub
* and updates PROP_FUSE (reboots if changed).
*/
private void updateFusePropFromSettings() {
- Boolean settingsFuseFlag = SystemProperties.getBoolean((FeatureFlagUtils.PERSIST_PREFIX
- + FeatureFlagUtils.SETTINGS_FUSE_FLAG), false);
- Slog.d(TAG, "The value of Settings Fuse Flag is " + settingsFuseFlag);
- if (SystemProperties.getBoolean(StorageManager.PROP_FUSE, false) != settingsFuseFlag) {
+ String settingsFuseFlag = SystemProperties.get(StorageManager.PROP_SETTINGS_FUSE);
+ Slog.d(TAG, "The value of Settings Fuse Flag is "
+ + (settingsFuseFlag == null || settingsFuseFlag.isEmpty()
+ ? "null" : settingsFuseFlag));
+ // Set default value of PROP_SETTINGS_FUSE and PROP_FUSE if it
+ // is unset (neither true nor false, this happens only on the first boot
+ // after wiping data partition).
+ if (settingsFuseFlag == null || settingsFuseFlag.isEmpty()) {
+ SystemProperties.set(StorageManager.PROP_SETTINGS_FUSE, "false");
+ SystemProperties.set(StorageManager.PROP_FUSE, "false");
+ return;
+ }
+
+ if (!SystemProperties.get(StorageManager.PROP_FUSE).equals(settingsFuseFlag)) {
Slog.d(TAG, "Set persist.sys.fuse to " + settingsFuseFlag);
- SystemProperties.set(StorageManager.PROP_FUSE, Boolean.toString(settingsFuseFlag));
+ SystemProperties.set(StorageManager.PROP_FUSE, settingsFuseFlag);
// Perform hard reboot to kick policy into place
mContext.getSystemService(PowerManager.class).reboot("Reboot device for FUSE system"
+ "property change to take effect");
@@ -3097,14 +3105,6 @@ class StorageManagerService extends IStorageManager.Stub
@Override
public void mkdirs(String callingPkg, String appPath) {
- if (mIsFuseEnabled) {
- // TODO(b/144332951): Calling into Vold is risky because the FUSE daemon can go down
- // anytime and Vold will hang forever. We should either remove this call
- // or at least call into the FUSE daemon to mkdir instead
- Slog.w(TAG, "Not making dir for package " + callingPkg + " with path " + appPath);
- return;
- }
-
final int callingUid = Binder.getCallingUid();
final int userId = UserHandle.getUserId(callingUid);
final UserEnvironment userEnv = new UserEnvironment(userId);
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index b560761aa94f..6bc117be7f65 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -1313,7 +1313,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
// only CarrierService with carrier privilege rule should have the permission
int[] subIds = Arrays.stream(SubscriptionManager.from(mContext)
.getActiveSubscriptionIdList(false))
- .filter(i -> TelephonyPermissions.checkCarrierPrivilegeForSubId(i)).toArray();
+ .filter(i -> TelephonyPermissions.checkCarrierPrivilegeForSubId(mContext,
+ i)).toArray();
if (ArrayUtils.isEmpty(subIds)) {
loge("notifyCarrierNetworkChange without carrier privilege");
// the active subId does not have carrier privilege.
@@ -2304,7 +2305,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
return;
}
- TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(
+ TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(mContext,
SubscriptionManager.getDefaultSubscriptionId(), method);
}
diff --git a/services/core/java/com/android/server/am/LmkdConnection.java b/services/core/java/com/android/server/am/LmkdConnection.java
index d1e09db39e41..f41c36404c50 100644
--- a/services/core/java/com/android/server/am/LmkdConnection.java
+++ b/services/core/java/com/android/server/am/LmkdConnection.java
@@ -18,6 +18,7 @@ package com.android.server.am;
import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_ERROR;
import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT;
+
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -35,9 +36,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
-import java.util.concurrent.locks.Condition;
-import java.util.concurrent.locks.ReentrantLock;
-import java.util.concurrent.TimeUnit;
/**
* Lmkd connection to communicate with lowmemorykiller daemon.
@@ -46,7 +44,7 @@ public class LmkdConnection {
private static final String TAG = TAG_WITH_CLASS_NAME ? "LmkdConnection" : TAG_AM;
// lmkd reply max size in bytes
- private static final int LMKD_REPLY_MAX_SIZE = 8;
+ private static final int LMKD_REPLY_MAX_SIZE = 12;
// connection listener interface
interface LmkdConnectionListener {
@@ -64,6 +62,15 @@ public class LmkdConnection {
*/
public boolean isReplyExpected(ByteBuffer replyBuf, ByteBuffer dataReceived,
int receivedLen);
+
+ /**
+ * Handle the received message if it's unsolicited.
+ *
+ * @param dataReceived The buffer holding received data
+ * @param receivedLen Size of the data received
+ * @return True if the message has been handled correctly, false otherwise.
+ */
+ boolean handleUnsolicitedMessage(ByteBuffer dataReceived, int receivedLen);
}
private final MessageQueue mMsgQueue;
@@ -187,17 +194,17 @@ public class LmkdConnection {
mReplyBuf.rewind();
// wakeup the waiting thread
mReplyBufLock.notifyAll();
- } else {
- // received asynchronous or unexpected packet
+ } else if (!mListener.handleUnsolicitedMessage(mInputBuf, len)) {
+ // received unexpected packet
// treat this as an error
mReplyBuf = null;
mReplyBufLock.notifyAll();
- Slog.e(TAG, "Received unexpected packet from lmkd");
+ Slog.e(TAG, "Received an unexpected packet from lmkd");
}
- } else {
+ } else if (!mListener.handleUnsolicitedMessage(mInputBuf, len)) {
// received asynchronous communication from lmkd
- // we don't support this yet
- Slog.w(TAG, "Received an asynchronous packet from lmkd");
+ // but we don't recognize it.
+ Slog.w(TAG, "Received an unexpected packet from lmkd");
}
}
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 209b1d2e7fb9..5378f438fea5 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -278,14 +278,16 @@ public final class ProcessList {
// LMK_PROCREMOVE <pid>
// LMK_PROCPURGE
// LMK_GETKILLCNT
+ // LMK_PROCKILL
static final byte LMK_TARGET = 0;
static final byte LMK_PROCPRIO = 1;
static final byte LMK_PROCREMOVE = 2;
static final byte LMK_PROCPURGE = 3;
static final byte LMK_GETKILLCNT = 4;
+ static final byte LMK_PROCKILL = 5; // Note: this is an unsolicated command
// lmkd reconnect delay in msecs
- private final static long LMDK_RECONNECT_DELAY_MS = 1000;
+ private static final long LMKD_RECONNECT_DELAY_MS = 1000;
/**
* How long between a process kill and we actually receive its death recipient
@@ -391,6 +393,12 @@ public final class ProcessList {
ActiveUids mActiveUids;
/**
+ * The listener who is intereted with the lmkd kills.
+ */
+ @GuardedBy("mService")
+ private LmkdKillListener mLmkdKillListener = null;
+
+ /**
* The currently running isolated processes.
*/
final SparseArray<ProcessRecord> mIsolatedProcesses = new SparseArray<>();
@@ -408,6 +416,13 @@ public final class ProcessList {
private PlatformCompat mPlatformCompat = null;
+ interface LmkdKillListener {
+ /**
+ * Called when there is a process kill by lmkd.
+ */
+ void onLmkdKillOccurred(int pid, int uid);
+ }
+
final class IsolatedUidRange {
@VisibleForTesting
public final int mFirstUid;
@@ -560,7 +575,8 @@ public final class ProcessList {
final class KillHandler extends Handler {
static final int KILL_PROCESS_GROUP_MSG = 4000;
- static final int LMDK_RECONNECT_MSG = 4001;
+ static final int LMKD_RECONNECT_MSG = 4001;
+ static final int LMKD_PROC_KILLED_MSG = 4002;
public KillHandler(Looper looper) {
super(looper, null, true);
@@ -574,15 +590,18 @@ public final class ProcessList {
Process.killProcessGroup(msg.arg1 /* uid */, msg.arg2 /* pid */);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
- case LMDK_RECONNECT_MSG:
+ case LMKD_RECONNECT_MSG:
if (!sLmkdConnection.connect()) {
Slog.i(TAG, "Failed to connect to lmkd, retry after " +
- LMDK_RECONNECT_DELAY_MS + " ms");
- // retry after LMDK_RECONNECT_DELAY_MS
+ LMKD_RECONNECT_DELAY_MS + " ms");
+ // retry after LMKD_RECONNECT_DELAY_MS
sKillHandler.sendMessageDelayed(sKillHandler.obtainMessage(
- KillHandler.LMDK_RECONNECT_MSG), LMDK_RECONNECT_DELAY_MS);
+ KillHandler.LMKD_RECONNECT_MSG), LMKD_RECONNECT_DELAY_MS);
}
break;
+ case LMKD_PROC_KILLED_MSG:
+ handleLmkdProcKilled(msg.arg1 /* pid */, msg.arg2 /* uid */);
+ break;
default:
super.handleMessage(msg);
@@ -623,7 +642,7 @@ public final class ProcessList {
Slog.w(TAG, "Lost connection to lmkd");
// start reconnection after delay to let lmkd restart
sKillHandler.sendMessageDelayed(sKillHandler.obtainMessage(
- KillHandler.LMDK_RECONNECT_MSG), LMDK_RECONNECT_DELAY_MS);
+ KillHandler.LMKD_RECONNECT_MSG), LMKD_RECONNECT_DELAY_MS);
}
@Override
@@ -634,6 +653,26 @@ public final class ProcessList {
return (receivedLen == replyBuf.array().length &&
dataReceived.getInt(0) == replyBuf.getInt(0));
}
+
+ @Override
+ public boolean handleUnsolicitedMessage(ByteBuffer dataReceived,
+ int receivedLen) {
+ if (receivedLen < 4) {
+ return false;
+ }
+ switch (dataReceived.getInt(0)) {
+ case LMK_PROCKILL:
+ if (receivedLen != 12) {
+ return false;
+ }
+ sKillHandler.obtainMessage(KillHandler.LMKD_PROC_KILLED_MSG,
+ dataReceived.getInt(4), dataReceived.getInt(8))
+ .sendToTarget();
+ return true;
+ default:
+ return false;
+ }
+ }
}
);
}
@@ -1310,10 +1349,10 @@ public final class ProcessList {
if (!sLmkdConnection.isConnected()) {
// try to connect immediately and then keep retrying
sKillHandler.sendMessage(
- sKillHandler.obtainMessage(KillHandler.LMDK_RECONNECT_MSG));
+ sKillHandler.obtainMessage(KillHandler.LMKD_RECONNECT_MSG));
// wait for connection retrying 3 times (up to 3 seconds)
- if (!sLmkdConnection.waitForConnection(3 * LMDK_RECONNECT_DELAY_MS)) {
+ if (!sLmkdConnection.waitForConnection(3 * LMKD_RECONNECT_DELAY_MS)) {
return false;
}
}
@@ -3405,4 +3444,28 @@ public final class ProcessList {
}
}
}
+
+ void setLmkdKillListener(final LmkdKillListener listener) {
+ synchronized (mService) {
+ mLmkdKillListener = listener;
+ }
+ }
+
+ private void handleLmkdProcKilled(final int pid, final int uid) {
+ // Log only now
+ if (DEBUG_PROCESSES) {
+ Slog.i(TAG, "lmkd kill: pid=" + pid + " uid=" + uid);
+ }
+
+ if (mService == null) {
+ return;
+ }
+ // Notify any interesed party regarding the lmkd kills
+ synchronized (mService) {
+ final LmkdKillListener listener = mLmkdKillListener;
+ if (listener != null) {
+ mService.mHandler.post(()-> listener.onLmkdKillOccurred(pid, uid));
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 366766e2e47b..14f96540bc6a 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -20,6 +20,7 @@ import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION
import static android.app.AppOpsManager.MAX_PRIORITY_UID_STATE;
import static android.app.AppOpsManager.MIN_PRIORITY_UID_STATE;
import static android.app.AppOpsManager.OP_CAMERA;
+import static android.app.AppOpsManager.OP_COARSE_LOCATION;
import static android.app.AppOpsManager.OP_FLAGS_ALL;
import static android.app.AppOpsManager.OP_NONE;
import static android.app.AppOpsManager.OP_PLAY_AUDIO;
@@ -1642,6 +1643,13 @@ public class AppOpsService extends IAppOpsService.Stub {
return;
}
+ // STOPSHIP: Remove this check once we are sure no one is doing it.
+ if (code == OP_COARSE_LOCATION && mode != AppOpsManager.opToDefaultMode(code)) {
+ Slog.wtf(TAG, "Trying to setMode() instead of setUidMode(), " + "code=" + code
+ + ", uid=" + uid + ", packageName=" + packageName + ", mode=" + mode
+ + ", callingUid=" + Binder.getCallingUid(), new RuntimeException());
+ }
+
synchronized (this) {
UidState uidState = getUidStateLocked(uid, false);
Op op = getOpLocked(code, uid, packageName, isPrivileged, true);
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 661451b882cc..90615864d1d0 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -68,9 +68,6 @@ public class AudioDeviceInventory {
private @NonNull AudioDeviceBroker mDeviceBroker;
- // cache of the address of the last dock the device was connected to
- private String mDockAddress;
-
// Monitoring of audio routes. Protected by mAudioRoutes.
final AudioRoutesInfo mCurAudioRoutes = new AudioRoutesInfo();
final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers =
@@ -187,7 +184,7 @@ public class AudioDeviceInventory {
int a2dpVolume = btInfo.getVolume();
if (AudioService.DEBUG_DEVICES) {
Log.d(TAG, "onSetA2dpSinkConnectionState btDevice=" + btDevice + " state="
- + state + " is dock=" + btDevice.isBluetoothDock() + " vol=" + a2dpVolume);
+ + state + " vol=" + a2dpVolume);
}
String address = btDevice.getAddress();
if (!BluetoothAdapter.checkBluetoothAddress(address)) {
@@ -215,42 +212,17 @@ public class AudioDeviceInventory {
mDeviceBroker.postBluetoothA2dpDeviceConfigChange(btDevice);
}
} else {
- if (btDevice.isBluetoothDock()) {
- if (state == BluetoothProfile.STATE_DISCONNECTED) {
- // introduction of a delay for transient disconnections of docks when
- // power is rapidly turned off/on, this message will be canceled if
- // we reconnect the dock under a preset delay
- makeA2dpDeviceUnavailableLater(address,
- AudioDeviceBroker.BTA2DP_DOCK_TIMEOUT_MS);
- // the next time isConnected is evaluated, it will be false for the dock
- }
- } else {
- makeA2dpDeviceUnavailableNow(address, di.mDeviceCodecFormat);
- }
+ makeA2dpDeviceUnavailableNow(address, di.mDeviceCodecFormat);
}
- } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
- if (btDevice.isBluetoothDock()) {
- // this could be a reconnection after a transient disconnection
- mDeviceBroker.cancelA2dpDockTimeout();
- mDockAddress = address;
- } else {
- // this could be a connection of another A2DP device before the timeout of
- // a dock: cancel the dock timeout, and make the dock unavailable now
- if (mDeviceBroker.hasScheduledA2dpDockTimeout() && mDockAddress != null) {
- mDeviceBroker.cancelA2dpDockTimeout();
- makeA2dpDeviceUnavailableNow(mDockAddress,
- AudioSystem.AUDIO_FORMAT_DEFAULT);
- }
- }
- if (a2dpVolume != -1) {
- mDeviceBroker.postSetVolumeIndexOnDevice(AudioSystem.STREAM_MUSIC,
- // convert index to internal representation in VolumeStreamState
- a2dpVolume * 10,
- AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, "onSetA2dpSinkConnectionState");
- }
- makeA2dpDeviceAvailable(address, BtHelper.getName(btDevice),
- "onSetA2dpSinkConnectionState", a2dpCodec);
}
+ if (a2dpVolume != -1) {
+ mDeviceBroker.postSetVolumeIndexOnDevice(AudioSystem.STREAM_MUSIC,
+ // convert index to internal representation in VolumeStreamState
+ a2dpVolume * 10,
+ AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, "onSetA2dpSinkConnectionState");
+ }
+ makeA2dpDeviceAvailable(address, BtHelper.getName(btDevice),
+ "onSetA2dpSinkConnectionState", a2dpCodec);
}
}
@@ -723,9 +695,6 @@ public class AudioDeviceInventory {
DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
// Remove A2DP routes as well
setCurrentAudioRouteNameIfPossible(null);
- if (mDockAddress == address) {
- mDockAddress = null;
- }
}
@GuardedBy("mConnectedDevices")
diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java
index 7ce63c5f89b2..af6840382c11 100644
--- a/services/core/java/com/android/server/display/DisplayDevice.java
+++ b/services/core/java/com/android/server/display/DisplayDevice.java
@@ -157,6 +157,24 @@ abstract class DisplayDevice {
public void setRequestedColorModeLocked(int colorMode) {
}
+ /**
+ * Sends the Auto Low Latency Mode (ALLM) signal over HDMI, or requests an internal display to
+ * switch to a low-latency mode.
+ *
+ * @param on Whether to set ALLM on or off.
+ */
+ public void setAutoLowLatencyModeLocked(boolean on) {
+ }
+
+ /**
+ * Sends a ContentType=Game signal over HDMI, or requests an internal display to switch to a
+ * game mode (generally lower latency).
+ *
+ * @param on Whether to send a ContentType=Game signal or not
+ */
+ public void setGameContentTypeLocked(boolean on) {
+ }
+
public void onOverlayChangedLocked() {
}
diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
index 729ea1772066..ac41434a1b5c 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
@@ -207,6 +207,16 @@ final class DisplayDeviceInfo {
public Display.HdrCapabilities hdrCapabilities;
/**
+ * Indicates whether this display supports Auto Low Latency Mode.
+ */
+ public boolean allmSupported;
+
+ /**
+ * Indicates whether this display suppors Game content type.
+ */
+ public boolean gameContentTypeSupported;
+
+ /**
* The nominal apparent density of the display in DPI used for layout calculations.
* This density is sensitive to the viewing distance. A big TV and a tablet may have
* the same apparent density even though the pixels on the TV are much bigger than
@@ -337,6 +347,8 @@ final class DisplayDeviceInfo {
|| !Arrays.equals(supportedModes, other.supportedModes)
|| !Arrays.equals(supportedColorModes, other.supportedColorModes)
|| !Objects.equals(hdrCapabilities, other.hdrCapabilities)
+ || allmSupported != other.allmSupported
+ || gameContentTypeSupported != other.gameContentTypeSupported
|| densityDpi != other.densityDpi
|| xDpi != other.xDpi
|| yDpi != other.yDpi
@@ -371,6 +383,8 @@ final class DisplayDeviceInfo {
colorMode = other.colorMode;
supportedColorModes = other.supportedColorModes;
hdrCapabilities = other.hdrCapabilities;
+ allmSupported = other.allmSupported;
+ gameContentTypeSupported = other.gameContentTypeSupported;
densityDpi = other.densityDpi;
xDpi = other.xDpi;
yDpi = other.yDpi;
@@ -400,6 +414,8 @@ final class DisplayDeviceInfo {
sb.append(", colorMode ").append(colorMode);
sb.append(", supportedColorModes ").append(Arrays.toString(supportedColorModes));
sb.append(", HdrCapabilities ").append(hdrCapabilities);
+ sb.append(", allmSupported ").append(allmSupported);
+ sb.append(", gameContentTypeSupported ").append(gameContentTypeSupported);
sb.append(", density ").append(densityDpi);
sb.append(", ").append(xDpi).append(" x ").append(yDpi).append(" dpi");
sb.append(", appVsyncOff ").append(appVsyncOffsetNanos);
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index d20191dd1f85..3e8a726fb443 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -569,6 +569,23 @@ public final class DisplayManagerService extends SystemService {
}
}
+ private void setPreferMinimalPostProcessingLocked(int displayId, boolean isPreferred) {
+ LogicalDisplay display = mLogicalDisplays.get(displayId);
+ if (display != null) {
+ DisplayDeviceInfo info =
+ display.getPrimaryDisplayDeviceLocked().getDisplayDeviceInfoLocked();
+
+ if (info.allmSupported) {
+ display.setAutoLowLatencyMode(isPreferred);
+ }
+ if (info.gameContentTypeSupported) {
+ display.setGameContentType(isPreferred);
+ }
+
+ scheduleTraversalLocked(false);
+ }
+ }
+
private DisplayInfo getDisplayInfoInternal(int displayId, int callingUid) {
synchronized (mSyncRoot) {
LogicalDisplay display = mLogicalDisplays.get(displayId);
@@ -1192,7 +1209,8 @@ public final class DisplayManagerService extends SystemService {
}
private void setDisplayPropertiesInternal(int displayId, boolean hasContent,
- float requestedRefreshRate, int requestedModeId, boolean inTraversal) {
+ float requestedRefreshRate, int requestedModeId, boolean preferMinimalPostProcessing,
+ boolean inTraversal) {
synchronized (mSyncRoot) {
LogicalDisplay display = mLogicalDisplays.get(displayId);
if (display == null) {
@@ -1215,6 +1233,8 @@ public final class DisplayManagerService extends SystemService {
}
mDisplayModeDirector.getAppRequestObserver().setAppRequestedMode(
displayId, requestedModeId);
+
+ setPreferMinimalPostProcessingLocked(displayId, preferMinimalPostProcessing);
}
}
@@ -2343,6 +2363,7 @@ public final class DisplayManagerService extends SystemService {
}
private final class LocalService extends DisplayManagerInternal {
+
@Override
public void initPowerManagement(final DisplayPowerCallbacks callbacks, Handler handler,
SensorManager sensorManager) {
@@ -2431,9 +2452,10 @@ public final class DisplayManagerService extends SystemService {
@Override
public void setDisplayProperties(int displayId, boolean hasContent,
- float requestedRefreshRate, int requestedMode, boolean inTraversal) {
+ float requestedRefreshRate, int requestedMode, boolean preferMinimalPostProcessing,
+ boolean inTraversal) {
setDisplayPropertiesInternal(displayId, hasContent, requestedRefreshRate,
- requestedMode, inTraversal);
+ requestedMode, preferMinimalPostProcessing, inTraversal);
}
@Override
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 308c755a0868..86ba845edb54 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -181,6 +181,10 @@ final class LocalDisplayAdapter extends DisplayAdapter {
private int mActiveColorMode;
private boolean mActiveColorModeInvalid;
private Display.HdrCapabilities mHdrCapabilities;
+ private boolean mAllmSupported;
+ private boolean mGameContentTypeSupported;
+ private boolean mAllmRequested;
+ private boolean mGameContentTypeRequested;
private boolean mSidekickActive;
private SidekickInternal mSidekickInternal;
@@ -204,6 +208,8 @@ final class LocalDisplayAdapter extends DisplayAdapter {
mBacklight = null;
}
mHdrCapabilities = SurfaceControl.getHdrCapabilities(displayToken);
+ mAllmSupported = SurfaceControl.getAutoLowLatencyModeSupport(displayToken);
+ mGameContentTypeSupported = SurfaceControl.getGameContentTypeSupport(displayToken);
}
@Override
@@ -397,6 +403,8 @@ final class LocalDisplayAdapter extends DisplayAdapter {
mInfo.defaultModeId = mDefaultModeId;
mInfo.supportedModes = getDisplayModes(mSupportedModes);
mInfo.colorMode = mActiveColorMode;
+ mInfo.allmSupported = mAllmSupported;
+ mInfo.gameContentTypeSupported = mGameContentTypeSupported;
mInfo.supportedColorModes =
new int[mSupportedColorModes.size()];
for (int i = 0; i < mSupportedColorModes.size(); i++) {
@@ -767,6 +775,40 @@ final class LocalDisplayAdapter extends DisplayAdapter {
}
@Override
+ public void setAutoLowLatencyModeLocked(boolean on) {
+ if (mAllmRequested == on) {
+ return;
+ }
+
+ mAllmRequested = on;
+
+ if (!mAllmSupported) {
+ Slog.d(TAG, "Unable to set ALLM because the connected display "
+ + "does not support ALLM.");
+ return;
+ }
+
+ SurfaceControl.setAutoLowLatencyMode(getDisplayTokenLocked(), on);
+ }
+
+ @Override
+ public void setGameContentTypeLocked(boolean on) {
+ if (mGameContentTypeRequested == on) {
+ return;
+ }
+
+ mGameContentTypeRequested = on;
+
+ if (!mGameContentTypeSupported) {
+ Slog.d(TAG, "Unable to set game content type because the connected "
+ + "display does not support game content type.");
+ return;
+ }
+
+ SurfaceControl.setGameContentType(getDisplayTokenLocked(), on);
+ }
+
+ @Override
public void dumpLocked(PrintWriter pw) {
super.dumpLocked(pw);
pw.println("mPhysicalDisplayId=" + mPhysicalDisplayId);
@@ -782,6 +824,10 @@ final class LocalDisplayAdapter extends DisplayAdapter {
pw.println("mState=" + Display.stateToString(mState));
pw.println("mBrightness=" + mBrightness);
pw.println("mBacklight=" + mBacklight);
+ pw.println("mAllmSupported=" + mAllmSupported);
+ pw.println("mAllmRequested=" + mAllmRequested);
+ pw.println("mGameContentTypeSupported" + mGameContentTypeSupported);
+ pw.println("mGameContentTypeRequested" + mGameContentTypeRequested);
pw.println("mDisplayInfos=");
for (int i = 0; i < mDisplayInfos.length; i++) {
pw.println(" " + mDisplayInfos[i]);
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index f4b2dc8cfc98..4649374a57a1 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -89,6 +89,8 @@ final class LogicalDisplay {
private int[] mAllowedDisplayModes = new int[0];
private int mRequestedColorMode;
+ private boolean mShouldSetAllm;
+ private boolean mShouldSetGameContentType;
// The display offsets to apply to the display projection.
private int mDisplayOffsetX;
@@ -282,6 +284,8 @@ final class LogicalDisplay {
deviceInfo.supportedColorModes,
deviceInfo.supportedColorModes.length);
mBaseDisplayInfo.hdrCapabilities = deviceInfo.hdrCapabilities;
+ mBaseDisplayInfo.minimalPostProcessingSupported =
+ deviceInfo.allmSupported || deviceInfo.gameContentTypeSupported;
mBaseDisplayInfo.logicalDensityDpi = deviceInfo.densityDpi;
mBaseDisplayInfo.physicalXDpi = deviceInfo.xDpi;
mBaseDisplayInfo.physicalYDpi = deviceInfo.yDpi;
@@ -361,6 +365,9 @@ final class LogicalDisplay {
device.setRequestedColorModeLocked(0);
}
+ device.setAutoLowLatencyModeLocked(mShouldSetAllm);
+ device.setGameContentTypeLocked(mShouldSetGameContentType);
+
// Only grab the display info now as it may have been changed based on the requests above.
final DisplayInfo displayInfo = getDisplayInfoLocked();
final DisplayDeviceInfo displayDeviceInfo = device.getDisplayDeviceInfoLocked();
@@ -482,6 +489,26 @@ final class LogicalDisplay {
mRequestedColorMode = colorMode;
}
+ /**
+ * Sends the Auto Low Latency Mode (ALLM) signal over HDMI, or requests an internal display to
+ * switch to a low-latency mode.
+ *
+ * @param on Whether to set ALLM on or off.
+ */
+ public void setAutoLowLatencyMode(boolean on) {
+ mShouldSetAllm = on;
+ }
+
+ /**
+ * Sends a ContentType=Game signal over HDMI, or requests an internal display to switch to a
+ * game mode (generally lower latency).
+ *
+ * @param on Whether to send a ContentType=Game signal or not
+ */
+ public void setGameContentType(boolean on) {
+ mShouldSetGameContentType = on;
+ }
+
/** Returns the pending requested color mode. */
public int getRequestedColorModeLocked() {
return mRequestedColorMode;
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java b/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java
index 52cede2121bd..23b5c1411b0e 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java
@@ -250,7 +250,11 @@ final class HdmiCecKeycode {
new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_LEFT_UP),
// No Android keycode defined for CEC_KEYCODE_LEFT_DOWN
new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_LEFT_DOWN),
+ // Both KEYCODE_HOME and KEYCODE_MENU keys are sent as CEC_KEYCODE_ROOT_MENU
+ // NOTE that the HOME key is not usually forwarded.
+ // When CEC_KEYCODE_ROOT_MENU is received, it is translated to KEYCODE_HOME
new KeycodeEntry(KeyEvent.KEYCODE_HOME, CEC_KEYCODE_ROOT_MENU),
+ new KeycodeEntry(KeyEvent.KEYCODE_MENU, CEC_KEYCODE_ROOT_MENU),
new KeycodeEntry(KeyEvent.KEYCODE_SETTINGS, CEC_KEYCODE_SETUP_MENU),
new KeycodeEntry(KeyEvent.KEYCODE_TV_CONTENTS_MENU, CEC_KEYCODE_CONTENTS_MENU, false),
// No Android keycode defined for CEC_KEYCODE_FAVORITE_MENU
diff --git a/services/core/java/com/android/server/location/LocationSettingsStore.java b/services/core/java/com/android/server/location/LocationSettingsStore.java
index 3d18d4a12e44..f625452975c0 100644
--- a/services/core/java/com/android/server/location/LocationSettingsStore.java
+++ b/services/core/java/com/android/server/location/LocationSettingsStore.java
@@ -34,6 +34,7 @@ import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArraySet;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.server.SystemConfig;
@@ -113,6 +114,16 @@ public class LocationSettingsStore {
() -> SystemConfig.getInstance().getAllowIgnoreLocationSettings(), handler);
}
+ /** Called when system is ready. */
+ public synchronized void onSystemReady() {
+ mLocationMode.register();
+ mBackgroundThrottleIntervalMs.register();
+ mLocationPackageBlacklist.register();
+ mLocationPackageWhitelist.register();
+ mBackgroundThrottlePackageWhitelist.register();
+ mIgnoreSettingsPackageWhitelist.register();
+ }
+
/**
* Retrieve if location is enabled or not.
*/
@@ -300,13 +311,25 @@ public class LocationSettingsStore {
private abstract static class ObservingSetting extends ContentObserver {
private final CopyOnWriteArrayList<UserSettingChangedListener> mListeners;
+ private boolean mRegistered;
- private ObservingSetting(Context context, String settingName, Handler handler) {
+ private ObservingSetting(Handler handler) {
super(handler);
mListeners = new CopyOnWriteArrayList<>();
+ }
+
+ protected boolean isRegistered() {
+ return mRegistered;
+ }
+
+ protected void register(Context context, Uri uri) {
+ if (mRegistered) {
+ return;
+ }
context.getContentResolver().registerContentObserver(
- getUriFor(settingName), false, this, UserHandle.USER_ALL);
+ uri, false, this, UserHandle.USER_ALL);
+ mRegistered = true;
}
public void addListener(UserSettingChangedListener listener) {
@@ -317,8 +340,6 @@ public class LocationSettingsStore {
mListeners.remove(listener);
}
- protected abstract Uri getUriFor(String settingName);
-
@Override
public void onChange(boolean selfChange, Uri uri, int userId) {
for (UserSettingChangedListener listener : mListeners) {
@@ -333,20 +354,19 @@ public class LocationSettingsStore {
private final String mSettingName;
private IntegerSecureSetting(Context context, String settingName, Handler handler) {
- super(context, settingName, handler);
+ super(handler);
mContext = context;
mSettingName = settingName;
}
+ private void register() {
+ register(mContext, Settings.Secure.getUriFor(mSettingName));
+ }
+
public int getValueForUser(int defaultValue, int userId) {
return Settings.Secure.getIntForUser(mContext.getContentResolver(), mSettingName,
defaultValue, userId);
}
-
- @Override
- protected Uri getUriFor(String settingName) {
- return Settings.Secure.getUriFor(settingName);
- }
}
private static class StringListCachedSecureSetting extends ObservingSetting {
@@ -354,31 +374,44 @@ public class LocationSettingsStore {
private final Context mContext;
private final String mSettingName;
- private int mCachedUserId = UserHandle.USER_NULL;
+ @GuardedBy("this")
+ private int mCachedUserId;
+ @GuardedBy("this")
private List<String> mCachedValue;
private StringListCachedSecureSetting(Context context, String settingName,
Handler handler) {
- super(context, settingName, handler);
+ super(handler);
mContext = context;
mSettingName = settingName;
+
+ mCachedUserId = UserHandle.USER_NULL;
+ }
+
+ public synchronized void register() {
+ register(mContext, Settings.Secure.getUriFor(mSettingName));
}
public synchronized List<String> getValueForUser(int userId) {
Preconditions.checkArgument(userId != UserHandle.USER_NULL);
+ List<String> value = mCachedValue;
if (userId != mCachedUserId) {
String setting = Settings.Secure.getStringForUser(mContext.getContentResolver(),
mSettingName, userId);
if (TextUtils.isEmpty(setting)) {
- mCachedValue = Collections.emptyList();
+ value = Collections.emptyList();
} else {
- mCachedValue = Arrays.asList(setting.split(","));
+ value = Arrays.asList(setting.split(","));
+ }
+
+ if (isRegistered()) {
+ mCachedUserId = userId;
+ mCachedValue = value;
}
- mCachedUserId = userId;
}
- return mCachedValue;
+ return value;
}
public synchronized void invalidateForUser(int userId) {
@@ -393,11 +426,6 @@ public class LocationSettingsStore {
invalidateForUser(userId);
super.onChange(selfChange, uri, userId);
}
-
- @Override
- protected Uri getUriFor(String settingName) {
- return Settings.Secure.getUriFor(settingName);
- }
}
private static class LongGlobalSetting extends ObservingSetting {
@@ -406,20 +434,19 @@ public class LocationSettingsStore {
private final String mSettingName;
private LongGlobalSetting(Context context, String settingName, Handler handler) {
- super(context, settingName, handler);
+ super(handler);
mContext = context;
mSettingName = settingName;
}
+ public void register() {
+ register(mContext, Settings.Global.getUriFor(mSettingName));
+ }
+
public long getValue(long defaultValue) {
return Settings.Global.getLong(mContext.getContentResolver(), mSettingName,
defaultValue);
}
-
- @Override
- protected Uri getUriFor(String settingName) {
- return Settings.Global.getUriFor(settingName);
- }
}
private static class StringSetCachedGlobalSetting extends ObservingSetting {
@@ -428,29 +455,42 @@ public class LocationSettingsStore {
private final String mSettingName;
private final Supplier<ArraySet<String>> mBaseValuesSupplier;
+ @GuardedBy("this")
private boolean mValid;
+ @GuardedBy("this")
private ArraySet<String> mCachedValue;
private StringSetCachedGlobalSetting(Context context, String settingName,
Supplier<ArraySet<String>> baseValuesSupplier, Handler handler) {
- super(context, settingName, handler);
+ super(handler);
mContext = context;
mSettingName = settingName;
mBaseValuesSupplier = baseValuesSupplier;
+
+ mValid = false;
+ }
+
+ public synchronized void register() {
+ register(mContext, Settings.Global.getUriFor(mSettingName));
}
public synchronized Set<String> getValue() {
+ ArraySet<String> value = mCachedValue;
if (!mValid) {
- mCachedValue = new ArraySet<>(mBaseValuesSupplier.get());
+ value = new ArraySet<>(mBaseValuesSupplier.get());
String setting = Settings.Global.getString(mContext.getContentResolver(),
mSettingName);
if (!TextUtils.isEmpty(setting)) {
- mCachedValue.addAll(Arrays.asList(setting.split(",")));
+ value.addAll(Arrays.asList(setting.split(",")));
+ }
+
+ if (isRegistered()) {
+ mValid = true;
+ mCachedValue = value;
}
- mValid = true;
}
- return mCachedValue;
+ return value;
}
public synchronized void invalidate() {
@@ -463,10 +503,5 @@ public class LocationSettingsStore {
invalidate();
super.onChange(selfChange, uri, userId);
}
-
- @Override
- protected Uri getUriFor(String settingName) {
- return Settings.Global.getUriFor(settingName);
- }
}
}
diff --git a/services/core/java/com/android/server/LocationUsageLogger.java b/services/core/java/com/android/server/location/LocationUsageLogger.java
index a8a3cc47cfb0..755438b1a413 100644
--- a/services/core/java/com/android/server/LocationUsageLogger.java
+++ b/services/core/java/com/android/server/location/LocationUsageLogger.java
@@ -14,37 +14,113 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.location;
+
+import static com.android.server.LocationManagerService.TAG;
import android.app.ActivityManager;
import android.location.Geofence;
import android.location.LocationManager;
import android.location.LocationRequest;
-import android.os.SystemClock;
import android.stats.location.LocationStatsEnums;
import android.util.Log;
import android.util.StatsLog;
+import com.android.internal.annotations.GuardedBy;
+
import java.time.Instant;
/**
* Logger for Location API usage logging.
*/
public class LocationUsageLogger {
- private static final String TAG = "LocationUsageLogger";
- private static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
private static final int ONE_SEC_IN_MILLIS = 1000;
private static final int ONE_MINUTE_IN_MILLIS = 60000;
private static final int ONE_HOUR_IN_MILLIS = 3600000;
- private long mLastApiUsageLogHour = 0;
+ private static final int API_USAGE_LOG_HOURLY_CAP = 60;
+ @GuardedBy("this")
+ private long mLastApiUsageLogHour = 0;
+ @GuardedBy("this")
private int mApiUsageLogHourlyCount = 0;
- private static final int API_USAGE_LOG_HOURLY_CAP = 60;
+ /**
+ * Log a location API usage event.
+ */
+ public void logLocationApiUsage(int usageType, int apiInUse,
+ String packageName, LocationRequest locationRequest,
+ boolean hasListener, boolean hasIntent,
+ Geofence geofence, int activityImportance) {
+ try {
+ if (hitApiUsageLogCap()) {
+ return;
+ }
+
+ boolean isLocationRequestNull = locationRequest == null;
+ boolean isGeofenceNull = geofence == null;
+
+ StatsLog.write(StatsLog.LOCATION_MANAGER_API_USAGE_REPORTED, usageType,
+ apiInUse, packageName,
+ isLocationRequestNull
+ ? LocationStatsEnums.PROVIDER_UNKNOWN
+ : bucketizeProvider(locationRequest.getProvider()),
+ isLocationRequestNull
+ ? LocationStatsEnums.QUALITY_UNKNOWN
+ : locationRequest.getQuality(),
+ isLocationRequestNull
+ ? LocationStatsEnums.INTERVAL_UNKNOWN
+ : bucketizeInterval(locationRequest.getInterval()),
+ isLocationRequestNull
+ ? LocationStatsEnums.DISTANCE_UNKNOWN
+ : bucketizeDistance(
+ locationRequest.getSmallestDisplacement()),
+ isLocationRequestNull ? 0 : locationRequest.getNumUpdates(),
+ // only log expireIn for USAGE_STARTED
+ isLocationRequestNull || usageType == LocationStatsEnums.USAGE_ENDED
+ ? LocationStatsEnums.EXPIRATION_UNKNOWN
+ : bucketizeExpireIn(locationRequest.getExpireIn()),
+ getCallbackType(apiInUse, hasListener, hasIntent),
+ isGeofenceNull
+ ? LocationStatsEnums.RADIUS_UNKNOWN
+ : bucketizeRadius(geofence.getRadius()),
+ categorizeActivityImportance(activityImportance));
+ } catch (Exception e) {
+ // Swallow exceptions to avoid crashing LMS.
+ Log.w(TAG, "Failed to log API usage to statsd.", e);
+ }
+ }
- private static int providerNameToStatsdEnum(String provider) {
+ /**
+ * Log a location API usage event.
+ */
+ public void logLocationApiUsage(int usageType, int apiInUse, String providerName) {
+ try {
+ if (hitApiUsageLogCap()) {
+ return;
+ }
+
+ StatsLog.write(StatsLog.LOCATION_MANAGER_API_USAGE_REPORTED, usageType, apiInUse,
+ /* package_name= */ null,
+ bucketizeProvider(providerName),
+ LocationStatsEnums.QUALITY_UNKNOWN,
+ LocationStatsEnums.INTERVAL_UNKNOWN,
+ LocationStatsEnums.DISTANCE_UNKNOWN,
+ /* numUpdates= */ 0,
+ LocationStatsEnums.EXPIRATION_UNKNOWN,
+ getCallbackType(
+ apiInUse,
+ /* isListenerNull= */ true,
+ /* isIntentNull= */ true),
+ /* bucketizedRadius= */ 0,
+ LocationStatsEnums.IMPORTANCE_UNKNOWN);
+ } catch (Exception e) {
+ Log.w(TAG, "Failed to log API usage to statsd.", e);
+ }
+ }
+
+ private static int bucketizeProvider(String provider) {
if (LocationManager.NETWORK_PROVIDER.equals(provider)) {
return LocationStatsEnums.PROVIDER_NETWORK;
} else if (LocationManager.GPS_PROVIDER.equals(provider)) {
@@ -58,8 +134,7 @@ public class LocationUsageLogger {
}
}
- private static int bucketizeIntervalToStatsdEnum(long interval) {
- // LocationManager already converts negative values to 0.
+ private static int bucketizeInterval(long interval) {
if (interval < ONE_SEC_IN_MILLIS) {
return LocationStatsEnums.INTERVAL_BETWEEN_0_SEC_AND_1_SEC;
} else if (interval < ONE_SEC_IN_MILLIS * 5) {
@@ -75,9 +150,8 @@ public class LocationUsageLogger {
}
}
- private static int bucketizeSmallestDisplacementToStatsdEnum(float smallestDisplacement) {
- // LocationManager already converts negative values to 0.
- if (smallestDisplacement == 0) {
+ private static int bucketizeDistance(float smallestDisplacement) {
+ if (smallestDisplacement <= 0) {
return LocationStatsEnums.DISTANCE_ZERO;
} else if (smallestDisplacement > 0 && smallestDisplacement <= 100) {
return LocationStatsEnums.DISTANCE_BETWEEN_0_AND_100;
@@ -86,7 +160,7 @@ public class LocationUsageLogger {
}
}
- private static int bucketizeRadiusToStatsdEnum(float radius) {
+ private static int bucketizeRadius(float radius) {
if (radius < 0) {
return LocationStatsEnums.RADIUS_NEGATIVE;
} else if (radius < 100) {
@@ -104,14 +178,11 @@ public class LocationUsageLogger {
}
}
- private static int getBucketizedExpireIn(long expireAt) {
- if (expireAt == Long.MAX_VALUE) {
+ private static int bucketizeExpireIn(long expireIn) {
+ if (expireIn == Long.MAX_VALUE) {
return LocationStatsEnums.EXPIRATION_NO_EXPIRY;
}
- long elapsedRealtime = SystemClock.elapsedRealtime();
- long expireIn = Math.max(0, expireAt - elapsedRealtime);
-
if (expireIn < 20 * ONE_SEC_IN_MILLIS) {
return LocationStatsEnums.EXPIRATION_BETWEEN_0_AND_20_SEC;
} else if (expireIn < ONE_MINUTE_IN_MILLIS) {
@@ -129,8 +200,8 @@ public class LocationUsageLogger {
if (importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
return LocationStatsEnums.IMPORTANCE_TOP;
} else if (importance == ActivityManager
- .RunningAppProcessInfo
- .IMPORTANCE_FOREGROUND_SERVICE) {
+ .RunningAppProcessInfo
+ .IMPORTANCE_FOREGROUND_SERVICE) {
return LocationStatsEnums.IMPORTANCE_FORGROUND_SERVICE;
} else {
return LocationStatsEnums.IMPORTANCE_BACKGROUND;
@@ -154,117 +225,16 @@ public class LocationUsageLogger {
}
}
- // Update the hourly count of APIUsage log event.
- // Returns false if hit the hourly log cap.
- private boolean checkApiUsageLogCap() {
- if (D) {
- Log.d(TAG, "checking APIUsage log cap.");
- }
-
+ private synchronized boolean hitApiUsageLogCap() {
long currentHour = Instant.now().toEpochMilli() / ONE_HOUR_IN_MILLIS;
if (currentHour > mLastApiUsageLogHour) {
mLastApiUsageLogHour = currentHour;
mApiUsageLogHourlyCount = 0;
- return true;
+ return false;
} else {
mApiUsageLogHourlyCount = Math.min(
- mApiUsageLogHourlyCount + 1, API_USAGE_LOG_HOURLY_CAP);
- return mApiUsageLogHourlyCount < API_USAGE_LOG_HOURLY_CAP;
- }
- }
-
- /**
- * Log a Location API usage event to Statsd.
- * Logging event is capped at 60 per hour. Usage events exceeding
- * the cap will be dropped by LocationUsageLogger.
- */
- public void logLocationApiUsage(int usageType, int apiInUse,
- String packageName, LocationRequest locationRequest,
- boolean hasListener, boolean hasIntent,
- Geofence geofence, int activityImportance) {
- try {
- if (!checkApiUsageLogCap()) {
- return;
- }
-
- boolean isLocationRequestNull = locationRequest == null;
- boolean isGeofenceNull = geofence == null;
- if (D) {
- Log.d(TAG, "log API Usage to statsd. usageType: " + usageType + ", apiInUse: "
- + apiInUse + ", packageName: " + (packageName == null ? "" : packageName)
- + ", locationRequest: "
- + (isLocationRequestNull ? "" : locationRequest.toString())
- + ", hasListener: " + hasListener
- + ", hasIntent: " + hasIntent
- + ", geofence: "
- + (isGeofenceNull ? "" : geofence.toString())
- + ", importance: " + activityImportance);
- }
-
- StatsLog.write(StatsLog.LOCATION_MANAGER_API_USAGE_REPORTED, usageType,
- apiInUse, packageName,
- isLocationRequestNull
- ? LocationStatsEnums.PROVIDER_UNKNOWN
- : providerNameToStatsdEnum(locationRequest.getProvider()),
- isLocationRequestNull
- ? LocationStatsEnums.QUALITY_UNKNOWN
- : locationRequest.getQuality(),
- isLocationRequestNull
- ? LocationStatsEnums.INTERVAL_UNKNOWN
- : bucketizeIntervalToStatsdEnum(locationRequest.getInterval()),
- isLocationRequestNull
- ? LocationStatsEnums.DISTANCE_UNKNOWN
- : bucketizeSmallestDisplacementToStatsdEnum(
- locationRequest.getSmallestDisplacement()),
- isLocationRequestNull ? 0 : locationRequest.getNumUpdates(),
- // only log expireIn for USAGE_STARTED
- isLocationRequestNull || usageType == LocationStatsEnums.USAGE_ENDED
- ? LocationStatsEnums.EXPIRATION_UNKNOWN
- : getBucketizedExpireIn(locationRequest.getExpireAt()),
- getCallbackType(apiInUse, hasListener, hasIntent),
- isGeofenceNull
- ? LocationStatsEnums.RADIUS_UNKNOWN
- : bucketizeRadiusToStatsdEnum(geofence.getRadius()),
- categorizeActivityImportance(activityImportance));
- } catch (Exception e) {
- // Swallow exceptions to avoid crashing LMS.
- Log.w(TAG, "Failed to log API usage to statsd.", e);
- }
- }
-
- /**
- * Log a Location API usage event to Statsd.
- * Logging event is capped at 60 per hour. Usage events exceeding
- * the cap will be dropped by LocationUsageLogger.
- */
- public void logLocationApiUsage(int usageType, int apiInUse, String providerName) {
- try {
- if (!checkApiUsageLogCap()) {
- return;
- }
-
- if (D) {
- Log.d(TAG, "log API Usage to statsd. usageType: " + usageType + ", apiInUse: "
- + apiInUse + ", providerName: " + providerName);
- }
-
- StatsLog.write(StatsLog.LOCATION_MANAGER_API_USAGE_REPORTED, usageType, apiInUse,
- /* package_name= */ null,
- providerNameToStatsdEnum(providerName),
- LocationStatsEnums.QUALITY_UNKNOWN,
- LocationStatsEnums.INTERVAL_UNKNOWN,
- LocationStatsEnums.DISTANCE_UNKNOWN,
- /* numUpdates= */ 0,
- LocationStatsEnums.EXPIRATION_UNKNOWN,
- getCallbackType(
- apiInUse,
- /* isListenerNull= */ true,
- /* isIntentNull= */ true),
- /* bucketizedRadius= */ 0,
- LocationStatsEnums.IMPORTANCE_UNKNOWN);
- } catch (Exception e) {
- // Swallow exceptions to avoid crashing LMS.
- Log.w(TAG, "Failed to log API usage to statsd.", e);
+ mApiUsageLogHourlyCount + 1, API_USAGE_LOG_HOURLY_CAP);
+ return mApiUsageLogHourlyCount >= API_USAGE_LOG_HOURLY_CAP;
}
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationComparator.java b/services/core/java/com/android/server/notification/NotificationComparator.java
index bc051547a53f..7098435ca299 100644
--- a/services/core/java/com/android/server/notification/NotificationComparator.java
+++ b/services/core/java/com/android/server/notification/NotificationComparator.java
@@ -23,7 +23,6 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.provider.Settings;
import android.telecom.TelecomManager;
import com.android.internal.util.NotificationMessagingUtil;
@@ -55,14 +54,9 @@ public class NotificationComparator
final boolean isLeftHighImportance = leftImportance >= IMPORTANCE_DEFAULT;
final boolean isRightHighImportance = rightImportance >= IMPORTANCE_DEFAULT;
- // With new interruption model, prefer importance bucket above all other criteria
- // (to ensure buckets are contiguous)
- if (Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.NOTIFICATION_NEW_INTERRUPTION_MODEL, 1) == 1) {
- if (isLeftHighImportance != isRightHighImportance) {
- // by importance bucket, high importance higher than low importance
- return -1 * Boolean.compare(isLeftHighImportance, isRightHighImportance);
- }
+ if (isLeftHighImportance != isRightHighImportance) {
+ // by importance bucket, high importance higher than low importance
+ return -1 * Boolean.compare(isLeftHighImportance, isRightHighImportance);
}
// first all colorized notifications
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 642b500c5e3c..4558adb59db4 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -14144,7 +14144,7 @@ public class PackageManagerService extends IPackageManager.Stub
verification.putExtra(PackageManager.EXTRA_VERIFICATION_ID, verificationId);
verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_PACKAGE,
- installSource.installerPackageName);
+ installSource.initiatingPackageName);
verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALL_FLAGS,
installFlags);
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 5adb64876ad4..8ce1a52afd0c 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -321,7 +321,10 @@ public class PermissionManagerService extends IPermissionManager.Stub {
public void onPermissionUpdatedNotifyListener(@UserIdInt int[] updatedUserIds, boolean sync,
int uid) {
onPermissionUpdated(updatedUserIds, sync);
- mOnPermissionChangeListeners.onPermissionsChanged(uid);
+ for (int i = 0; i < updatedUserIds.length; i++) {
+ int userUid = UserHandle.getUid(updatedUserIds[i], UserHandle.getAppId(uid));
+ mOnPermissionChangeListeners.onPermissionsChanged(userUid);
+ }
}
public void onInstallPermissionUpdatedNotifyListener(int uid) {
onInstallPermissionUpdated();
@@ -733,7 +736,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
// Install and runtime permissions are stored in different places,
// so figure out what permission changed and persist the change.
if (permissionsState.getInstallPermissionState(permName) != null) {
- callback.onInstallPermissionUpdatedNotifyListener(pkg.getUid());
+ int userUid = UserHandle.getUid(userId, UserHandle.getAppId(pkg.getUid()));
+ callback.onInstallPermissionUpdatedNotifyListener(userUid);
} else if (permissionsState.getRuntimePermissionState(permName, userId) != null
|| hadState) {
callback.onPermissionUpdatedNotifyListener(new int[]{userId}, false,
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index 6da8fb4b1edb..cc1cddd3a111 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -41,12 +41,12 @@ import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.Vibrator;
+import android.telephony.TelephonyManager;
import android.util.ArrayMap;
import android.util.Log;
import android.util.TimingsTraceLog;
import android.view.WindowManager;
-import com.android.internal.telephony.ITelephony;
import com.android.server.LocalServices;
import com.android.server.RescueParty;
import com.android.server.pm.PackageManagerService;
@@ -586,19 +586,15 @@ public final class ShutdownThread extends Thread {
TimingsTraceLog shutdownTimingsTraceLog = newTimingsLog();
boolean radioOff;
- final ITelephony phone =
- ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
+ TelephonyManager telephonyManager = mContext.getSystemService(
+ TelephonyManager.class);
- try {
- radioOff = phone == null || !phone.needMobileRadioShutdown();
- if (!radioOff) {
- Log.w(TAG, "Turning off cellular radios...");
- metricStarted(METRIC_RADIO);
- phone.shutdownMobileRadios();
- }
- } catch (RemoteException ex) {
- Log.e(TAG, "RemoteException during radio shutdown", ex);
- radioOff = true;
+ radioOff = telephonyManager == null
+ || !telephonyManager.isAnyRadioPoweredOn();
+ if (!radioOff) {
+ Log.w(TAG, "Turning off cellular radios...");
+ metricStarted(METRIC_RADIO);
+ telephonyManager.shutdownAllRadios();
}
Log.i(TAG, "Waiting for Radio...");
@@ -613,12 +609,7 @@ public final class ShutdownThread extends Thread {
}
if (!radioOff) {
- try {
- radioOff = !phone.needMobileRadioShutdown();
- } catch (RemoteException ex) {
- Log.e(TAG, "RemoteException during radio shutdown", ex);
- radioOff = true;
- }
+ radioOff = !telephonyManager.isAnyRadioPoweredOn();
if (radioOff) {
Log.i(TAG, "Radio turned off.");
metricEnded(METRIC_RADIO);
diff --git a/services/core/java/com/android/server/storage/StorageSessionController.java b/services/core/java/com/android/server/storage/StorageSessionController.java
index 46dd366f1909..aa3ab63a32bb 100644
--- a/services/core/java/com/android/server/storage/StorageSessionController.java
+++ b/services/core/java/com/android/server/storage/StorageSessionController.java
@@ -308,34 +308,6 @@ public final class StorageSessionController {
}
/**
- * Throws an {@link IllegalStateException} if {@code path} is not ready to be accessed by
- * {@code userId}.
- */
- // TODO(b/144332951): This is not used because it is racy. Right after checking a path
- // we can call into vold with that path and the FUSE daemon can go down. Improve or remove
- public void checkPathReadyForUser(int userId, String path) {
- if (!mIsFuseEnabled) {
- return;
- }
-
- if (mIsResetting) {
- throw new IllegalStateException("Connection resetting for user " + userId
- + " with path " + path);
- }
-
- StorageUserConnection connection = null;
- synchronized (mLock) {
- connection = mConnections.get(userId);
- }
-
- if (connection == null) {
- throw new IllegalStateException("Connection not ready for user " + userId
- + " with path " + path);
- }
- connection.checkPathReady(path);
- }
-
- /**
* Returns {@code true} if {@code vol} is an emulated or public volume,
* {@code false} otherwise
**/
diff --git a/services/core/java/com/android/server/storage/StorageUserConnection.java b/services/core/java/com/android/server/storage/StorageUserConnection.java
index 5c44eee4c789..10514ad7edcb 100644
--- a/services/core/java/com/android/server/storage/StorageUserConnection.java
+++ b/services/core/java/com/android/server/storage/StorageUserConnection.java
@@ -163,20 +163,6 @@ public final class StorageUserConnection {
mActiveConnection.close();
}
- /** Throws an {@link IllegalArgumentException} if {@code path} is not ready for access */
- public void checkPathReady(String path) {
- synchronized (mLock) {
- for (Session session : mSessions.values()) {
- if (session.upperPath != null && path.startsWith(session.upperPath)) {
- if (mActiveConnection.isActiveLocked(session)) {
- return;
- }
- }
- }
- throw new IllegalStateException("Path not ready " + path);
- }
- }
-
/** Returns all created sessions. */
public Set<String> getAllSessionIds() {
synchronized (mLock) {
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorService.java b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
index 34400ff6b484..172367a128cc 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorService.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
@@ -31,7 +31,6 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils;
import com.android.server.FgThread;
import com.android.server.SystemService;
-import com.android.server.timedetector.TimeDetectorStrategy.Callback;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -58,17 +57,16 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub {
@NonNull private final Handler mHandler;
@NonNull private final Context mContext;
- @NonNull private final Callback mCallback;
@NonNull private final TimeDetectorStrategy mTimeDetectorStrategy;
private static TimeDetectorService create(@NonNull Context context) {
- TimeDetectorStrategy timeDetector = new SimpleTimeDetectorStrategy();
+ TimeDetectorStrategy timeDetectorStrategy = new TimeDetectorStrategyImpl();
TimeDetectorStrategyCallbackImpl callback = new TimeDetectorStrategyCallbackImpl(context);
- timeDetector.initialize(callback);
+ timeDetectorStrategy.initialize(callback);
Handler handler = FgThread.getHandler();
TimeDetectorService timeDetectorService =
- new TimeDetectorService(context, handler, callback, timeDetector);
+ new TimeDetectorService(context, handler, timeDetectorStrategy);
// Wire up event listening.
ContentResolver contentResolver = context.getContentResolver();
@@ -85,10 +83,9 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub {
@VisibleForTesting
public TimeDetectorService(@NonNull Context context, @NonNull Handler handler,
- @NonNull Callback callback, @NonNull TimeDetectorStrategy timeDetectorStrategy) {
+ @NonNull TimeDetectorStrategy timeDetectorStrategy) {
mContext = Objects.requireNonNull(context);
mHandler = Objects.requireNonNull(handler);
- mCallback = Objects.requireNonNull(callback);
mTimeDetectorStrategy = Objects.requireNonNull(timeDetectorStrategy);
}
diff --git a/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
index 5a31bbc859c8..1b1ac6d3ed07 100644
--- a/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
@@ -46,7 +46,7 @@ import java.util.Map;
*
* <p>Most public methods are marked synchronized to ensure thread safety around internal state.
*/
-public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
+public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
private static final boolean DBG = false;
private static final String LOG_TAG = "SimpleTimeDetectorStrategy";
@@ -114,16 +114,10 @@ public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
}
@Override
- public synchronized void suggestManualTime(ManualTimeSuggestion suggestion) {
+ public synchronized void suggestManualTime(@NonNull ManualTimeSuggestion suggestion) {
final TimestampedValue<Long> newUtcTime = suggestion.getUtcTime();
- // We can validate the suggestion against the reference time clock.
- long elapsedRealtimeMillis = mCallback.elapsedRealtimeMillis();
- if (elapsedRealtimeMillis < newUtcTime.getReferenceTimeMillis()) {
- // elapsedRealtime clock went backwards?
- Slog.w(LOG_TAG, "New reference time is in the future? Ignoring."
- + " elapsedRealtimeMillis=" + elapsedRealtimeMillis
- + ", timeSuggestion=" + suggestion);
+ if (!validateSuggestionTime(newUtcTime, suggestion)) {
return;
}
@@ -202,62 +196,76 @@ public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
}
@GuardedBy("this")
- private boolean validateAndStorePhoneSuggestion(@NonNull PhoneTimeSuggestion timeSuggestion) {
- if (timeSuggestion.getUtcTime().getValue() == null) {
- Slog.w(LOG_TAG, "Suggestion utcTime contains null value"
- + " timeSuggestion=" + timeSuggestion);
+ private boolean validateAndStorePhoneSuggestion(@NonNull PhoneTimeSuggestion suggestion) {
+ TimestampedValue<Long> newUtcTime = suggestion.getUtcTime();
+ if (!validateSuggestionTime(newUtcTime, suggestion)) {
+ // There's probably nothing useful we can do: elsewhere we assume that reference
+ // times are in the past so just stop here.
return false;
}
- int phoneId = timeSuggestion.getPhoneId();
+ int phoneId = suggestion.getPhoneId();
LinkedList<PhoneTimeSuggestion> phoneSuggestions = mSuggestionByPhoneId.get(phoneId);
if (phoneSuggestions == null) {
// The first time we've seen this phoneId.
phoneSuggestions = new LinkedList<>();
mSuggestionByPhoneId.put(phoneId, phoneSuggestions);
} else if (phoneSuggestions.isEmpty()) {
- Slog.w(LOG_TAG, "Suggestions unexpectedly empty when adding"
- + " timeSuggestion=" + timeSuggestion);
+ Slog.w(LOG_TAG, "Suggestions unexpectedly empty when adding suggestion=" + suggestion);
}
if (!phoneSuggestions.isEmpty()) {
- PhoneTimeSuggestion previousSuggestion = phoneSuggestions.getFirst();
-
// We can log / discard suggestions with obvious issues with the reference time clock.
- long elapsedRealtimeMillis = mCallback.elapsedRealtimeMillis();
- TimestampedValue<Long> newTime = timeSuggestion.getUtcTime();
- if (elapsedRealtimeMillis < newTime.getReferenceTimeMillis()) {
- // elapsedRealtime clock went backwards?
- Slog.w(LOG_TAG, "New reference time is in the future?"
- + " elapsedRealtimeMillis=" + elapsedRealtimeMillis
- + ", timeSuggestion=" + timeSuggestion);
- // There's probably nothing useful we can do: elsewhere we assume that reference
- // times are in the past so just stop here.
+ PhoneTimeSuggestion previousSuggestion = phoneSuggestions.getFirst();
+ if (previousSuggestion == null
+ || previousSuggestion.getUtcTime() == null
+ || previousSuggestion.getUtcTime().getValue() == null) {
+ // This should be impossible given we only store validated suggestions.
+ Slog.w(LOG_TAG, "Previous suggestion is null or has a null time."
+ + " previousSuggestion=" + previousSuggestion
+ + ", suggestion=" + suggestion);
return false;
}
- if (previousSuggestion.getUtcTime() != null) {
- long referenceTimeDifference = TimestampedValue.referenceTimeDifference(
- timeSuggestion.getUtcTime(), previousSuggestion.getUtcTime());
- if (referenceTimeDifference < 0) {
- // The reference time is before the previously received suggestion. Ignore it.
- Slog.w(LOG_TAG, "Out of order phone suggestion received."
- + " referenceTimeDifference=" + referenceTimeDifference
- + " lastSuggestion=" + previousSuggestion
- + " newSuggestion=" + timeSuggestion);
- return false;
- }
+ long referenceTimeDifference = TimestampedValue.referenceTimeDifference(
+ newUtcTime, previousSuggestion.getUtcTime());
+ if (referenceTimeDifference < 0) {
+ // The reference time is before the previously received suggestion. Ignore it.
+ Slog.w(LOG_TAG, "Out of order phone suggestion received."
+ + " referenceTimeDifference=" + referenceTimeDifference
+ + " previousSuggestion=" + previousSuggestion
+ + " suggestion=" + suggestion);
+ return false;
}
}
// Store the latest suggestion.
- phoneSuggestions.addFirst(timeSuggestion);
+ phoneSuggestions.addFirst(suggestion);
if (phoneSuggestions.size() > KEEP_SUGGESTION_HISTORY_SIZE) {
phoneSuggestions.removeLast();
}
return true;
}
+ private boolean validateSuggestionTime(
+ @NonNull TimestampedValue<Long> newUtcTime, @NonNull Object suggestion) {
+ if (newUtcTime.getValue() == null) {
+ Slog.w(LOG_TAG, "Suggested time value is null. suggestion=" + suggestion);
+ return false;
+ }
+
+ // We can validate the suggestion against the reference time clock.
+ long elapsedRealtimeMillis = mCallback.elapsedRealtimeMillis();
+ if (elapsedRealtimeMillis < newUtcTime.getReferenceTimeMillis()) {
+ // elapsedRealtime clock went backwards?
+ Slog.w(LOG_TAG, "New reference time is in the future? Ignoring."
+ + " elapsedRealtimeMillis=" + elapsedRealtimeMillis
+ + ", suggestion=" + suggestion);
+ return false;
+ }
+ return true;
+ }
+
@GuardedBy("this")
private void doAutoTimeDetection(@NonNull String detectionReason) {
if (!mCallback.isAutoTimeDetectionEnabled()) {
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 8e66b149d344..18ed51a6cd5e 100644..100755
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -2943,6 +2943,16 @@ public final class TvInputManagerService extends SystemService {
if (state != null) {
setStateLocked(inputId, state, mCurrentUserId);
}
+ UserState userState = getOrCreateUserStateLocked(mCurrentUserId);
+ // Broadcast the event to all hardware inputs.
+ for (ServiceState serviceState : userState.serviceStateMap.values()) {
+ if (!serviceState.isHardware || serviceState.service == null) continue;
+ try {
+ serviceState.service.notifyHdmiDeviceUpdated(deviceInfo);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "error in notifyHdmiDeviceUpdated", e);
+ }
+ }
}
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 4e39daec0b83..5d9fb8a0e4fc 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1800,11 +1800,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
} else if (newTask || !processRunning || (taskSwitch && !activityCreated)) {
return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
} else if (taskSwitch && allowTaskSnapshot) {
- if (mWmService.mLowRamTaskSnapshotsAndRecents) {
- // For low RAM devices, we use the splash screen starting window instead of the
- // task snapshot starting window.
- return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
- }
return snapshot == null ? STARTING_WINDOW_TYPE_NONE
: snapshotOrientationSameAsTask(snapshot) || fromRecents
? STARTING_WINDOW_TYPE_SNAPSHOT : STARTING_WINDOW_TYPE_SPLASH_SCREEN;
@@ -2217,11 +2212,15 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return (info.flags & FLAG_ALWAYS_FOCUSABLE) != 0;
}
+ boolean windowsAreFocusable() {
+ return windowsAreFocusable(false /* fromUserTouch */);
+ }
+
// TODO: Does this really need to be different from isAlwaysFocusable()? For the activity side
// focusable means resumeable. I guess with that in mind maybe we should rename the other
// method to isResumeable() or something like that.
- boolean windowsAreFocusable() {
- if (mTargetSdk < Build.VERSION_CODES.Q) {
+ boolean windowsAreFocusable(boolean fromUserTouch) {
+ if (!fromUserTouch && mTargetSdk < Build.VERSION_CODES.Q) {
final int pid = getPid();
final ActivityRecord topFocusedAppOfMyProcess =
mWmService.mRoot.mTopFocusedAppByProcess.get(pid);
@@ -2235,7 +2234,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
&& getDisplay() != null;
}
- /** Move activity with its stack to front and make the stack focused. */
+ /**
+ * Move activity with its stack to front and make the stack focused.
+ * @param reason the reason to move to top
+ * @return {@code true} if the stack is focusable and has been moved to top or the activity
+ * is not yet resumed while the stack is already on top, {@code false} otherwise.
+ */
boolean moveFocusableActivityToTop(String reason) {
if (!isFocusable()) {
if (DEBUG_FOCUS) {
@@ -2256,7 +2260,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (DEBUG_FOCUS) {
Slog.d(TAG_FOCUS, "moveActivityStackToFront: already on top, activity=" + this);
}
- return false;
+ return !isState(RESUMED);
}
if (DEBUG_FOCUS) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index aa0e97318eed..fb84832dbbff 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -167,6 +167,7 @@ import android.os.UserHandle;
import android.util.ArraySet;
import android.util.DisplayMetrics;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.proto.ProtoOutputStream;
import android.view.Display;
@@ -174,6 +175,7 @@ import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.Gravity;
import android.view.ISystemGestureExclusionListener;
+import android.view.IWindow;
import android.view.InputChannel;
import android.view.InputDevice;
import android.view.InputWindowHandle;
@@ -563,6 +565,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
/** Corner radius that windows should have in order to match the display. */
private final float mWindowCornerRadius;
+ private final SparseArray<ShellRoot> mShellRoots = new SparseArray<>();
+
private final Consumer<WindowState> mUpdateWindowsForAnimator = w -> {
WindowStateAnimator winAnimator = w.mWinAnimator;
final ActivityRecord activity = w.mActivityRecord;
@@ -740,6 +744,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
// Update effect.
w.mObscured = mTmpApplySurfaceChangesTransactionState.obscured;
+
if (!mTmpApplySurfaceChangesTransactionState.obscured) {
final boolean isDisplayed = w.isDisplayedLw();
@@ -770,6 +775,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
mTmpApplySurfaceChangesTransactionState.preferredRefreshRate
= w.mAttrs.preferredRefreshRate;
}
+
+ mTmpApplySurfaceChangesTransactionState.preferMinimalPostProcessing
+ |= w.mAttrs.preferMinimalPostProcessing;
+
final int preferredModeId = getDisplayPolicy().getRefreshRatePolicy()
.getPreferredModeId(w);
if (mTmpApplySurfaceChangesTransactionState.preferredModeId == 0
@@ -1017,6 +1026,37 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
return token;
}
+ SurfaceControl addShellRoot(@NonNull IWindow client, int windowType) {
+ ShellRoot root = mShellRoots.get(windowType);
+ if (root != null) {
+ if (root.getClient() == client) {
+ return root.getSurfaceControl();
+ }
+ root.clear();
+ mShellRoots.remove(windowType);
+ }
+ root = new ShellRoot(client, this, windowType);
+ SurfaceControl rootLeash = root.getSurfaceControl();
+ if (rootLeash == null) {
+ // Root didn't finish initializing, so don't add it.
+ root.clear();
+ return null;
+ }
+ mShellRoots.put(windowType, root);
+ SurfaceControl out = new SurfaceControl();
+ out.copyFrom(rootLeash);
+ return out;
+ }
+
+ void removeShellRoot(int windowType) {
+ ShellRoot root = mShellRoots.get(windowType);
+ if (root == null) {
+ return;
+ }
+ root.clear();
+ mShellRoots.remove(windowType);
+ }
+
/** Changes the display the input window token is housed on to this one. */
void reParentWindowToken(WindowToken token) {
final DisplayContent prevDc = token.getDisplayContent();
@@ -3585,6 +3625,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
mLastHasContent,
mTmpApplySurfaceChangesTransactionState.preferredRefreshRate,
mTmpApplySurfaceChangesTransactionState.preferredModeId,
+ mTmpApplySurfaceChangesTransactionState.preferMinimalPostProcessing,
true /* inTraversal, must call performTraversalInTrans... below */);
final boolean wallpaperVisible = mWallpaperController.isWallpaperVisible();
@@ -3888,6 +3929,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
boolean displayHasContent;
boolean obscured;
boolean syswin;
+ boolean preferMinimalPostProcessing;
float preferredRefreshRate;
int preferredModeId;
@@ -3895,6 +3937,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
displayHasContent = false;
obscured = false;
syswin = false;
+ preferMinimalPostProcessing = false;
preferredRefreshRate = 0;
preferredModeId = 0;
}
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index c54fbd6b1726..e199b2887ed9 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -1144,6 +1144,7 @@ class RecentTasks {
// Trim the set of tasks to the active set
trimInactiveRecentTasks();
+ notifyTaskPersisterLocked(task, false /* flush */);
}
/**
diff --git a/services/core/java/com/android/server/wm/ShellRoot.java b/services/core/java/com/android/server/wm/ShellRoot.java
new file mode 100644
index 000000000000..9732637fdd4d
--- /dev/null
+++ b/services/core/java/com/android/server/wm/ShellRoot.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2019 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.wm;
+
+import android.annotation.NonNull;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+import android.view.IWindow;
+import android.view.SurfaceControl;
+
+/**
+ * Represents a piece of the hierarchy under which a client Shell can manage sub-windows.
+ */
+public class ShellRoot {
+ private static final String TAG = "ShellRoot";
+ private final DisplayContent mDisplayContent;
+ private IWindow mClient;
+ private WindowToken mToken;
+ private final IBinder.DeathRecipient mDeathRecipient;
+ private SurfaceControl mSurfaceControl = null;
+
+ ShellRoot(@NonNull IWindow client, @NonNull DisplayContent dc, final int windowType) {
+ mDisplayContent = dc;
+ mDeathRecipient = () -> mDisplayContent.removeShellRoot(windowType);
+ try {
+ client.asBinder().linkToDeath(mDeathRecipient, 0);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to add shell root for layer " + windowType + " on display "
+ + dc.getDisplayId(), e);
+ return;
+ }
+ mClient = client;
+ mToken = new WindowToken(
+ dc.mWmService, client.asBinder(), windowType, true, dc, true, false);
+ mSurfaceControl = mToken.makeChildSurface(null)
+ .setContainerLayer().setName("Shell Root Leash " + dc.getDisplayId()).build();
+ mToken.getPendingTransaction().show(mSurfaceControl);
+ }
+
+ void clear() {
+ if (mClient != null) {
+ mClient.asBinder().unlinkToDeath(mDeathRecipient, 0);
+ mClient = null;
+ }
+ if (mToken != null) {
+ mToken.removeImmediately();
+ mToken = null;
+ }
+ }
+
+ SurfaceControl getSurfaceControl() {
+ return mSurfaceControl;
+ }
+
+ IWindow getClient() {
+ return mClient;
+ }
+}
+
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
index 59155907823b..10f29960081e 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
@@ -54,7 +54,6 @@ class TaskSnapshotPersister {
private static final String REDUCED_POSTFIX = "_reduced";
private static final float REDUCED_SCALE = .5f;
private static final float LOW_RAM_REDUCED_SCALE = .6f;
- private static final float LOW_RAM_RECENTS_REDUCED_SCALE = .1f;
static final boolean DISABLE_FULL_SIZED_BITMAPS = ActivityManager.isLowRamDeviceStatic();
private static final long DELAY_MS = 100;
private static final int QUALITY = 95;
@@ -85,14 +84,8 @@ class TaskSnapshotPersister {
TaskSnapshotPersister(WindowManagerService service, DirectoryResolver resolver) {
mDirectoryResolver = resolver;
- if (service.mLowRamTaskSnapshotsAndRecents) {
- // Use very low res snapshots if we are using Go version of recents.
- mReducedScale = LOW_RAM_RECENTS_REDUCED_SCALE;
- } else {
- // TODO(122671846) Replace the low RAM value scale with the above when it is fully built
- mReducedScale = ActivityManager.isLowRamDeviceStatic()
- ? LOW_RAM_REDUCED_SCALE : REDUCED_SCALE;
- }
+ mReducedScale = ActivityManager.isLowRamDeviceStatic()
+ ? LOW_RAM_REDUCED_SCALE : REDUCED_SCALE;
mUse16BitFormat = service.mContext.getResources().getBoolean(
com.android.internal.R.bool.config_use16BitTaskSnapshotPixelFormat);
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index f45eb50f7f6c..b9f7ab344243 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -79,7 +79,6 @@ import static com.android.internal.util.LatencyTracker.ACTION_ROTATE_SCREEN;
import static com.android.server.LockGuard.INDEX_WINDOW;
import static com.android.server.LockGuard.installLock;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
-import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_BOOT;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS;
@@ -491,13 +490,6 @@ public class WindowManagerService extends IWindowManager.Stub
final long mDrawLockTimeoutMillis;
final boolean mAllowAnimationsInLowPowerMode;
- // TODO(b/122671846) Remove the flag below in favor of isLowRam once feature is stable
- /**
- * Use very low resolution task snapshots. Replaces task snapshot starting windows with
- * splashscreen starting windows. Used on low RAM devices to save memory.
- */
- final boolean mLowRamTaskSnapshotsAndRecents;
-
final boolean mAllowBootMessages;
final boolean mLimitedAlphaCompositing;
@@ -1114,8 +1106,6 @@ public class WindowManagerService extends IWindowManager.Stub
com.android.internal.R.bool.config_disableTransitionAnimation);
mPerDisplayFocusEnabled = context.getResources().getBoolean(
com.android.internal.R.bool.config_perDisplayFocusEnabled);
- mLowRamTaskSnapshotsAndRecents = context.getResources().getBoolean(
- com.android.internal.R.bool.config_lowRamTaskSnapshotsAndRecents);
mInputManager = inputManager; // Must be before createDisplayContentLocked.
mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
@@ -3721,6 +3711,26 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
+ public SurfaceControl addShellRoot(int displayId, IWindow client, int windowType) {
+ if (mContext.checkCallingOrSelfPermission(MANAGE_APP_TOKENS)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Must hold permission " + MANAGE_APP_TOKENS);
+ }
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ final DisplayContent dc = mRoot.getDisplayContent(displayId);
+ if (dc == null) {
+ return null;
+ }
+ return dc.addShellRoot(client, windowType);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ @Override
public int watchRotation(IRotationWatcher watcher, int displayId) {
final DisplayContent displayContent;
synchronized (mGlobalLock) {
@@ -7639,7 +7649,11 @@ public class WindowManagerService extends IWindowManager.Stub
return;
}
- handleDisplayFocusChange(touchedWindow);
+ final DisplayContent displayContent = touchedWindow.getDisplayContent();
+ if (!displayContent.isOnTop()) {
+ displayContent.getParent().positionChildAt(WindowContainer.POSITION_TOP, displayContent,
+ true /* includingParents */);
+ }
handleTaskFocusChange(touchedWindow.getTask());
}
@@ -7662,29 +7676,6 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- private void handleDisplayFocusChange(WindowState window) {
- final DisplayContent displayContent = window.getDisplayContent();
- if (displayContent == null) {
- return;
- }
-
- final WindowContainer parent = displayContent.getParent();
- if (parent != null && parent.getTopChild() != displayContent) {
- parent.positionChildAt(WindowContainer.POSITION_TOP, displayContent,
- true /* includingParents */);
- // For compatibility, only the topmost activity is allowed to be resumed for pre-Q
- // app. Ensure the topmost activities are resumed whenever a display is moved to top.
- // TODO(b/123761773): Investigate whether we can move this into
- // RootActivityContainer#updateTopResumedActivityIfNeeded(). Currently, it is risky
- // to do so because it seems possible to resume activities as part of a larger
- // transaction and it's too early to resume based on current order when performing
- // updateTopResumedActivityIfNeeded().
- // TODO(display-merge): Remove cast
- ((ActivityDisplay) displayContent).ensureActivitiesVisible(null /* starting */,
- 0 /* configChanges */, !PRESERVE_WINDOWS, true /* notifyClients */);
- }
- }
-
/**
* Assigns an InputChannel to a SurfaceControl and configures it to receive
* touch input according to it's on-screen geometry.
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 5b7f36d62094..eab8d05ce333 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2611,7 +2611,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
final boolean canReceiveKeys = isVisibleOrAdding()
&& (mViewVisibility == View.VISIBLE) && !mRemoveOnExit
&& ((mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) == 0)
- && (mActivityRecord == null || mActivityRecord.windowsAreFocusable())
+ && (mActivityRecord == null || mActivityRecord.windowsAreFocusable(fromUserTouch))
&& !cantReceiveTouchInput();
if (!canReceiveKeys) {
return false;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index ee0449d95e00..eb1753bdbee7 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -990,6 +990,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
"cross-profile-calendar-packages";
private static final String TAG_CROSS_PROFILE_CALENDAR_PACKAGES_NULL =
"cross-profile-calendar-packages-null";
+ private static final String TAG_CROSS_PROFILE_PACKAGES = "cross-profile-packages";
DeviceAdminInfo info;
@@ -1104,6 +1105,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
// is whitelisted.
List<String> mCrossProfileCalendarPackages = Collections.emptyList();
+ // The whitelist of packages that the admin has enabled to be able to request consent from
+ // the user to communicate cross-profile. By default, no packages are whitelisted, which is
+ // represented as an empty list.
+ List<String> mCrossProfilePackages = Collections.emptyList();
+
ActiveAdmin(DeviceAdminInfo _info, boolean parent) {
info = _info;
isParent = parent;
@@ -1329,6 +1335,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
writePackageListToXml(out, TAG_CROSS_PROFILE_CALENDAR_PACKAGES,
mCrossProfileCalendarPackages);
}
+ writePackageListToXml(out, TAG_CROSS_PROFILE_PACKAGES, mCrossProfilePackages);
}
void writeTextToXml(XmlSerializer out, String tag, String text) throws IOException {
@@ -1560,6 +1567,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
mCrossProfileCalendarPackages = readPackageList(parser, tag);
} else if (TAG_CROSS_PROFILE_CALENDAR_PACKAGES_NULL.equals(tag)) {
mCrossProfileCalendarPackages = null;
+ } else if (TAG_CROSS_PROFILE_PACKAGES.equals(tag)) {
+ mCrossProfilePackages = readPackageList(parser, tag);
} else {
Slog.w(LOG_TAG, "Unknown admin tag: " + tag);
XmlUtils.skipCurrentTag(parser);
@@ -1783,6 +1792,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
pw.print("mCrossProfileCalendarPackages=");
pw.println(mCrossProfileCalendarPackages);
}
+ pw.print("mCrossProfilePackages=");
+ pw.println(mCrossProfilePackages);
}
}
@@ -14645,6 +14656,35 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
@Override
+ public void setCrossProfilePackages(ComponentName who, List<String> packageNames) {
+ if (!mHasFeature) {
+ return;
+ }
+ Preconditions.checkNotNull(who, "ComponentName is null");
+ Preconditions.checkNotNull(packageNames, "Package names is null");
+ synchronized (getLockObject()) {
+ final ActiveAdmin admin =
+ getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ admin.mCrossProfilePackages = packageNames;
+ saveSettingsLocked(mInjector.userHandleGetCallingUserId());
+ }
+ }
+
+ @Override
+ public List<String> getCrossProfilePackages(ComponentName who) {
+ if (!mHasFeature) {
+ return Collections.emptyList();
+ }
+ Preconditions.checkNotNull(who, "ComponentName is null");
+
+ synchronized (getLockObject()) {
+ final ActiveAdmin admin = getActiveAdminForCallerLocked(
+ who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ return admin.mCrossProfilePackages;
+ }
+ }
+
+ @Override
public boolean isManagedKiosk() {
if (!mHasFeature) {
return false;
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index b6e501a785ef..6e29b6339e56 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -126,6 +126,7 @@ import com.android.server.os.DeviceIdentifiersPolicyService;
import com.android.server.os.SchedulingPolicyService;
import com.android.server.pm.BackgroundDexOptService;
import com.android.server.pm.CrossProfileAppsService;
+import com.android.server.pm.DataLoaderManagerService;
import com.android.server.pm.DynamicCodeLoggingService;
import com.android.server.pm.Installer;
import com.android.server.pm.LauncherAppsService;
@@ -321,6 +322,7 @@ public final class SystemServer {
private PackageManager mPackageManager;
private ContentResolver mContentResolver;
private EntropyMixer mEntropyMixer;
+ private DataLoaderManagerService mDataLoaderManagerService;
private boolean mOnlyCore;
private boolean mFirstBoot;
@@ -694,6 +696,12 @@ public final class SystemServer {
mWindowManagerGlobalLock = atm.getGlobalLock();
t.traceEnd();
+ // Data loader manager service needs to be started before package manager
+ t.traceBegin("StartDataLoaderManagerService");
+ mDataLoaderManagerService = mSystemServiceManager.startService(
+ DataLoaderManagerService.class);
+ t.traceEnd();
+
// Power manager needs to be started early because other services need it.
// Native daemons may be watching for it to be registered so it must be ready
// to handle incoming binder calls immediately (including being able to verify
diff --git a/services/tests/servicestests/src/com/android/server/GnssManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/GnssManagerServiceTest.java
index 9692c257079d..8b5444c2c55c 100644
--- a/services/tests/servicestests/src/com/android/server/GnssManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/GnssManagerServiceTest.java
@@ -61,6 +61,7 @@ import com.android.server.location.GnssMeasurementsProvider.GnssMeasurementProvi
import com.android.server.location.GnssNavigationMessageProvider;
import com.android.server.location.GnssNavigationMessageProvider.GnssNavigationMessageProviderNative;
import com.android.server.location.GnssStatusListenerHelper;
+import com.android.server.location.LocationUsageLogger;
import org.junit.Before;
import org.junit.Test;
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
index b5e5deb9ff59..67075edb0143 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
@@ -705,6 +705,26 @@ public class AccessibilityWindowManagerTest {
assertTrue(displayList.equals(mExpectedDisplayList));
}
+ @Test
+ public void setAccessibilityWindowIdToSurfaceMetadata()
+ throws RemoteException {
+ final IWindow token = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
+ true, USER_SYSTEM_ID);
+ int windowId = -1;
+ for (int i = 0; i < mA11yWindowTokens.size(); i++) {
+ if (mA11yWindowTokens.valueAt(i).equals(token)) {
+ windowId = mA11yWindowTokens.keyAt(i);
+ }
+ }
+ assertNotEquals("Returned token is not found in mA11yWindowTokens", -1, windowId);
+ verify(mMockWindowManagerInternal, times(1)).setAccessibilityIdToSurfaceMetadata(
+ token.asBinder(), windowId);
+
+ mA11yWindowManager.removeAccessibilityInteractionConnection(token);
+ verify(mMockWindowManagerInternal, times(1)).setAccessibilityIdToSurfaceMetadata(
+ token.asBinder(), -1);
+ }
+
private void startTrackingPerDisplay(int displayId) throws RemoteException {
ArrayList<WindowInfo> windowInfosForDisplay = new ArrayList<>();
// Adds RemoteAccessibilityConnection into AccessibilityWindowManager, and copy
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 43d8f927a57e..3f09f579369e 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -5548,6 +5548,38 @@ public class DevicePolicyManagerTest extends DpmTestBase {
mServiceContext.binder.restoreCallingIdentity(ident);
}
+ public void testGetCrossProfilePackages_notSet_returnsEmpty() {
+ setAsProfileOwner(admin1);
+ assertTrue(dpm.getCrossProfilePackages(admin1).isEmpty());
+ }
+
+ public void testGetCrossProfilePackages_notSet_dpmsReinitialized_returnsEmpty() {
+ setAsProfileOwner(admin1);
+
+ initializeDpms();
+
+ assertTrue(dpm.getCrossProfilePackages(admin1).isEmpty());
+ }
+
+ public void testGetCrossProfilePackages_whenSet_returnsEqual() {
+ setAsProfileOwner(admin1);
+ Set<String> packages = Collections.singleton("TEST_PACKAGE");
+
+ dpm.setCrossProfilePackages(admin1, packages);
+
+ assertEquals(packages, dpm.getCrossProfilePackages(admin1));
+ }
+
+ public void testGetCrossProfilePackages_whenSet_dpmsReinitialized_returnsEqual() {
+ setAsProfileOwner(admin1);
+ Set<String> packages = Collections.singleton("TEST_PACKAGE");
+
+ dpm.setCrossProfilePackages(admin1, packages);
+ initializeDpms();
+
+ assertEquals(packages, dpm.getCrossProfilePackages(admin1));
+ }
+
// admin1 is the outgoing DPC, adminAnotherPakcage is the incoming one.
private void assertDeviceOwnershipRevertedWithFakeTransferMetadata() throws Exception {
writeFakeTransferMetadataFile(UserHandle.USER_SYSTEM,
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
index 84b495f14c1f..72a7f508772b 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
@@ -38,8 +38,6 @@ import android.util.TimestampedValue;
import androidx.test.runner.AndroidJUnit4;
-import com.android.server.timedetector.TimeDetectorStrategy.Callback;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -52,7 +50,6 @@ public class TimeDetectorServiceTest {
private Context mMockContext;
private StubbedTimeDetectorStrategy mStubbedTimeDetectorStrategy;
- private Callback mMockCallback;
private TimeDetectorService mTimeDetectorService;
private HandlerThread mHandlerThread;
@@ -68,12 +65,10 @@ public class TimeDetectorServiceTest {
mHandlerThread.start();
mTestHandler = new TestHandler(mHandlerThread.getLooper());
- mMockCallback = mock(Callback.class);
mStubbedTimeDetectorStrategy = new StubbedTimeDetectorStrategy();
mTimeDetectorService = new TimeDetectorService(
- mMockContext, mTestHandler, mMockCallback,
- mStubbedTimeDetectorStrategy);
+ mMockContext, mTestHandler, mStubbedTimeDetectorStrategy);
}
@After
@@ -100,13 +95,13 @@ public class TimeDetectorServiceTest {
@Test
public void testSuggestManualTime() throws Exception {
- doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
+ doNothing().when(mMockContext).enforceCallingOrSelfPermission(anyString(), any());
ManualTimeSuggestion manualTimeSuggestion = createManualTimeSuggestion();
mTimeDetectorService.suggestManualTime(manualTimeSuggestion);
mTestHandler.assertTotalMessagesEnqueued(1);
- verify(mMockContext).enforceCallingPermission(
+ verify(mMockContext).enforceCallingOrSelfPermission(
eq(android.Manifest.permission.SET_TIME),
anyString());
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeDetectorStrategyTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
index 52e7d8197842..1aa3d8fe654b 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeDetectorStrategyTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
@@ -40,7 +40,7 @@ import org.junit.runner.RunWith;
import java.time.Duration;
@RunWith(AndroidJUnit4.class)
-public class SimpleTimeDetectorStrategyTest {
+public class TimeDetectorStrategyImplTest {
private static final TimestampedValue<Long> ARBITRARY_CLOCK_INITIALIZATION_INFO =
new TimestampedValue<>(
@@ -213,7 +213,7 @@ public class SimpleTimeDetectorStrategyTest {
}
// Let enough time pass that phone1Id's suggestion should now be too old.
- mScript.simulateTimePassing(SimpleTimeDetectorStrategy.PHONE_BUCKET_SIZE_MILLIS);
+ mScript.simulateTimePassing(TimeDetectorStrategyImpl.PHONE_BUCKET_SIZE_MILLIS);
// Make another suggestion with phone2Id. It should be used because the phoneId1
// is in an older "bucket".
@@ -394,7 +394,7 @@ public class SimpleTimeDetectorStrategyTest {
assertEquals(phoneSuggestion, mScript.peekBestPhoneSuggestion());
// Simulate time passing, long enough that phoneSuggestion is now too old.
- mScript.simulateTimePassing(SimpleTimeDetectorStrategy.PHONE_MAX_AGE_MILLIS);
+ mScript.simulateTimePassing(TimeDetectorStrategyImpl.PHONE_MAX_AGE_MILLIS);
// Look inside and check what the strategy considers the current best phone suggestion. It
// should still be the, it's just no longer used.
@@ -631,11 +631,11 @@ public class SimpleTimeDetectorStrategyTest {
private class Script {
private final FakeCallback mFakeCallback;
- private final SimpleTimeDetectorStrategy mTimeDetectorStrategy;
+ private final TimeDetectorStrategyImpl mTimeDetectorStrategy;
Script() {
mFakeCallback = new FakeCallback();
- mTimeDetectorStrategy = new SimpleTimeDetectorStrategy();
+ mTimeDetectorStrategy = new TimeDetectorStrategyImpl();
mTimeDetectorStrategy.initialize(mFakeCallback);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index b1cd93168c17..09d7b5412ee2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -41,8 +41,12 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -112,6 +116,7 @@ public class RecentTasksTest extends ActivityTestsBase {
@Before
public void setUp() throws Exception {
mTaskPersister = new TestTaskPersister(mContext.getFilesDir());
+ spyOn(mTaskPersister);
mDisplay = mRootActivityContainer.getActivityDisplay(DEFAULT_DISPLAY);
// Set the recent tasks we should use for testing in this class.
@@ -171,6 +176,46 @@ public class RecentTasksTest extends ActivityTestsBase {
}
@Test
+ public void testPersister() {
+ // Add some tasks, ensure the persister is woken
+ mRecentTasks.add(mTasks.get(0));
+ mRecentTasks.add(mTasks.get(1));
+ verify(mTaskPersister, times(1)).wakeup(eq(mTasks.get(0)), anyBoolean());
+ verify(mTaskPersister, times(1)).wakeup(eq(mTasks.get(1)), anyBoolean());
+ reset(mTaskPersister);
+
+ // Update a task, ensure the persister is woken
+ mRecentTasks.add(mTasks.get(0));
+ verify(mTaskPersister, times(1)).wakeup(eq(mTasks.get(0)), anyBoolean());
+ reset(mTaskPersister);
+
+ // Remove some tasks, ensure the persister is woken
+ mRecentTasks.remove(mTasks.get(0));
+ mRecentTasks.remove(mTasks.get(1));
+ verify(mTaskPersister, times(1)).wakeup(eq(mTasks.get(0)), anyBoolean());
+ verify(mTaskPersister, times(1)).wakeup(eq(mTasks.get(1)), anyBoolean());
+ reset(mTaskPersister);
+ }
+
+ @Test
+ public void testPersisterTrimmed() {
+ mRecentTasks.setOnlyTestVisibleRange();
+
+ // Limit the global maximum number of recent tasks to a fixed size
+ mRecentTasks.setGlobalMaxNumTasks(1 /* globalMaxNumTasks */);
+
+ mRecentTasks.add(mTasks.get(0));
+ verify(mTaskPersister, times(1)).wakeup(eq(mTasks.get(0)), anyBoolean());
+ reset(mTaskPersister);
+
+ // Add N+1 tasks to ensure the previous task is trimmed
+ mRecentTasks.add(mTasks.get(1));
+ verify(mTaskPersister, times(1)).wakeup(eq(mTasks.get(0)), anyBoolean());
+ verify(mTaskPersister, times(1)).wakeup(eq(mTasks.get(1)), anyBoolean());
+ assertTrimmed(mTasks.get(0));
+ }
+
+ @Test
public void testAddTasksNoMultiple_expectNoTrim() {
// Add same non-multiple-task document tasks will remove the task (to re-add it) but not
// trim it
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
index 735b9a1dcf2e..198b4c31249a 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
@@ -16,11 +16,14 @@
package com.android.server.soundtrigger;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.soundtrigger.IRecognitionStatusCallback;
+import android.hardware.soundtrigger.ModelParams;
import android.hardware.soundtrigger.SoundTrigger;
import android.hardware.soundtrigger.SoundTrigger.GenericRecognitionEvent;
import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel;
@@ -28,6 +31,7 @@ import android.hardware.soundtrigger.SoundTrigger.Keyphrase;
import android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionEvent;
import android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra;
import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
+import android.hardware.soundtrigger.SoundTrigger.ModelParamRange;
import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
import android.hardware.soundtrigger.SoundTrigger.RecognitionEvent;
@@ -605,6 +609,67 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
return STATUS_ERROR;
}
+ int setParameter(UUID modelId, @ModelParams int modelParam, int value) {
+ synchronized (mLock) {
+ MetricsLogger.count(mContext, "sth_set_parameter", 1);
+ if (modelId == null || mModule == null) {
+ return SoundTrigger.STATUS_ERROR;
+ }
+ ModelData modelData = mModelDataMap.get(modelId);
+ if (modelData == null) {
+ Slog.w(TAG, "SetParameter: Invalid model id:" + modelId);
+ return SoundTrigger.STATUS_BAD_VALUE;
+ }
+ if (!modelData.isModelLoaded()) {
+ Slog.i(TAG, "SetParameter: Given model is not loaded:" + modelId);
+ return SoundTrigger.STATUS_BAD_VALUE;
+ }
+
+ return mModule.setParameter(modelData.getHandle(), modelParam, value);
+ }
+ }
+
+ int getParameter(@NonNull UUID modelId, @ModelParams int modelParam)
+ throws UnsupportedOperationException, IllegalArgumentException {
+ synchronized (mLock) {
+ MetricsLogger.count(mContext, "sth_get_parameter", 1);
+ if (mModule == null) {
+ throw new UnsupportedOperationException("SoundTriggerModule not initialized");
+ }
+
+ ModelData modelData = mModelDataMap.get(modelId);
+ if (modelData == null) {
+ throw new IllegalArgumentException("Invalid model id:" + modelId);
+ }
+ if (!modelData.isModelLoaded()) {
+ throw new UnsupportedOperationException("Given model is not loaded:" + modelId);
+ }
+
+ return mModule.getParameter(modelData.getHandle(), modelParam);
+ }
+ }
+
+ @Nullable
+ ModelParamRange queryParameter(@NonNull UUID modelId, @ModelParams int modelParam) {
+ synchronized (mLock) {
+ MetricsLogger.count(mContext, "sth_query_parameter", 1);
+ if (mModule == null) {
+ return null;
+ }
+ ModelData modelData = mModelDataMap.get(modelId);
+ if (modelData == null) {
+ Slog.w(TAG, "queryParameter: Invalid model id:" + modelId);
+ return null;
+ }
+ if (!modelData.isModelLoaded()) {
+ Slog.i(TAG, "queryParameter: Given model is not loaded:" + modelId);
+ return null;
+ }
+
+ return mModule.queryParameter(modelData.getHandle(), modelParam);
+ }
+ }
+
//---- SoundTrigger.StatusListener methods
@Override
public void onRecognition(RecognitionEvent event) {
@@ -653,15 +718,15 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
}
ModelData model = getModelDataForLocked(event.soundModelHandle);
if (model == null || !model.isGenericModel()) {
- Slog.w(TAG, "Generic recognition event: Model does not exist for handle: " +
- event.soundModelHandle);
+ Slog.w(TAG, "Generic recognition event: Model does not exist for handle: "
+ + event.soundModelHandle);
return;
}
IRecognitionStatusCallback callback = model.getCallback();
if (callback == null) {
- Slog.w(TAG, "Generic recognition event: Null callback for model handle: " +
- event.soundModelHandle);
+ Slog.w(TAG, "Generic recognition event: Null callback for model handle: "
+ + event.soundModelHandle);
return;
}
@@ -678,8 +743,8 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
RecognitionConfig config = model.getRecognitionConfig();
if (config == null) {
- Slog.w(TAG, "Generic recognition event: Null RecognitionConfig for model handle: " +
- event.soundModelHandle);
+ Slog.w(TAG, "Generic recognition event: Null RecognitionConfig for model handle: "
+ + event.soundModelHandle);
return;
}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
index 1dd3972b56b4..96d2df125a3c 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
@@ -22,7 +22,9 @@ import static android.content.Context.BIND_FOREGROUND_SERVICE;
import static android.content.pm.PackageManager.GET_META_DATA;
import static android.content.pm.PackageManager.GET_SERVICES;
import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
+import static android.hardware.soundtrigger.SoundTrigger.STATUS_BAD_VALUE;
import static android.hardware.soundtrigger.SoundTrigger.STATUS_ERROR;
+import static android.hardware.soundtrigger.SoundTrigger.STATUS_NO_INIT;
import static android.hardware.soundtrigger.SoundTrigger.STATUS_OK;
import static android.provider.Settings.Global.MAX_SOUND_TRIGGER_DETECTION_SERVICE_OPS_PER_DAY;
import static android.provider.Settings.Global.SOUND_TRIGGER_DETECTION_SERVICE_OP_TIMEOUT;
@@ -39,9 +41,11 @@ import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.hardware.soundtrigger.IRecognitionStatusCallback;
+import android.hardware.soundtrigger.ModelParams;
import android.hardware.soundtrigger.SoundTrigger;
import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel;
import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
+import android.hardware.soundtrigger.SoundTrigger.ModelParamRange;
import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
import android.hardware.soundtrigger.SoundTrigger.SoundModel;
@@ -683,6 +687,101 @@ public class SoundTriggerService extends SystemService {
return properties;
}
}
+
+ @Override
+ public int setParameter(ParcelUuid soundModelId,
+ @ModelParams int modelParam, int value) {
+ enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
+ if (!isInitialized()) return STATUS_NO_INIT;
+ if (DEBUG) {
+ Slog.d(TAG, "setParameter(): id=" + soundModelId
+ + ", param=" + modelParam
+ + ", value=" + value);
+ }
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(
+ "setParameter(): id=" + soundModelId
+ + ", param=" + modelParam
+ + ", value=" + value));
+
+ synchronized (mLock) {
+ SoundModel soundModel = mLoadedModels.get(soundModelId.getUuid());
+ if (soundModel == null) {
+ Slog.e(TAG, soundModelId + " is not loaded. Loaded models: "
+ + mLoadedModels.toString());
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent("setParameter(): "
+ + soundModelId + " is not loaded"));
+
+ return STATUS_BAD_VALUE;
+ }
+
+ return mSoundTriggerHelper.setParameter(soundModel.uuid, modelParam, value);
+ }
+ }
+
+ @Override
+ public int getParameter(@NonNull ParcelUuid soundModelId,
+ @ModelParams int modelParam)
+ throws UnsupportedOperationException, IllegalArgumentException {
+ enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
+ if (!isInitialized()) {
+ throw new UnsupportedOperationException("SoundTriggerHelper not initialized");
+ }
+ if (DEBUG) {
+ Slog.d(TAG, "getParameter(): id=" + soundModelId
+ + ", param=" + modelParam);
+ }
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(
+ "getParameter(): id=" + soundModelId
+ + ", param=" + modelParam));
+
+ synchronized (mLock) {
+ SoundModel soundModel = mLoadedModels.get(soundModelId.getUuid());
+ if (soundModel == null) {
+ Slog.e(TAG, soundModelId + " is not loaded");
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent("getParameter(): "
+ + soundModelId + " is not loaded"));
+
+ throw new IllegalArgumentException("sound model is not loaded");
+ }
+
+ return mSoundTriggerHelper.getParameter(soundModel.uuid, modelParam);
+ }
+ }
+
+ @Override
+ @Nullable
+ public ModelParamRange queryParameter(@NonNull ParcelUuid soundModelId,
+ @ModelParams int modelParam) {
+ enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
+ if (!isInitialized()) return null;
+ if (DEBUG) {
+ Slog.d(TAG, "queryParameter(): id=" + soundModelId
+ + ", param=" + modelParam);
+ }
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(
+ "queryParameter(): id=" + soundModelId
+ + ", param=" + modelParam));
+
+ synchronized (mLock) {
+ SoundModel soundModel = mLoadedModels.get(soundModelId.getUuid());
+ if (soundModel == null) {
+ Slog.e(TAG, soundModelId + " is not loaded");
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(
+ "queryParameter(): "
+ + soundModelId + " is not loaded"));
+
+ return null;
+ }
+
+ return mSoundTriggerHelper.queryParameter(soundModel.uuid, modelParam);
+ }
+ }
}
/**
diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
index 86630b0eb991..4d01e330953a 100644
--- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
@@ -27,8 +27,6 @@ import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.Build;
import android.os.Process;
-import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.UserHandle;
import android.telephony.Rlog;
import android.telephony.SubscriptionManager;
@@ -42,7 +40,6 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
-import java.util.function.Supplier;
/** Utility class for Telephony permission enforcement. */
public final class TelephonyPermissions {
@@ -50,9 +47,6 @@ public final class TelephonyPermissions {
private static final boolean DBG = false;
- private static final Supplier<ITelephony> TELEPHONY_SUPPLIER = () ->
- ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));
-
/**
* Whether to disable the new device identifier access restrictions.
*/
@@ -138,49 +132,6 @@ public final class TelephonyPermissions {
public static boolean checkReadPhoneState(
Context context, int subId, int pid, int uid, String callingPackage,
@Nullable String callingFeatureId, String message) {
- return checkReadPhoneState(
- context, TELEPHONY_SUPPLIER, subId, pid, uid, callingPackage, callingFeatureId,
- message);
- }
-
- /**
- * Check whether the calling packages has carrier privileges for the passing subscription.
- * @return {@code true} if the caller has carrier privileges, {@false} otherwise.
- */
- public static boolean checkCarrierPrivilegeForSubId(int subId) {
- if (SubscriptionManager.isValidSubscriptionId(subId)
- && getCarrierPrivilegeStatus(TELEPHONY_SUPPLIER, subId, Binder.getCallingUid())
- == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
- return true;
- }
- return false;
- }
-
- /**
- * Check whether the app with the given pid/uid can read phone state.
- *
- * <p>This method behaves in one of the following ways:
- * <ul>
- * <li>return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission, the
- * READ_PHONE_STATE runtime permission, or carrier privileges on the given subId.
- * <li>throw SecurityException: if the caller didn't declare any of these permissions, or, for
- * apps which support runtime permissions, if the caller does not currently have any of
- * these permissions.
- * <li>return false: if the caller lacks all of these permissions and doesn't support runtime
- * permissions. This implies that the user revoked the ability to read phone state
- * manually (via AppOps). In this case we can't throw as it would break app compatibility,
- * so we return false to indicate that the calling function should return dummy data.
- * </ul>
- *
- * <p>Note: for simplicity, this method always returns false for callers using legacy
- * permissions and who have had READ_PHONE_STATE revoked, even if they are carrier-privileged.
- * Such apps should migrate to runtime permissions or stop requiring READ_PHONE_STATE on P+
- * devices.
- */
- @VisibleForTesting
- public static boolean checkReadPhoneState(
- Context context, Supplier<ITelephony> telephonySupplier, int subId, int pid, int uid,
- String callingPackage, @Nullable String callingFeatureId, String message) {
try {
context.enforcePermission(
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, pid, uid, message);
@@ -195,7 +146,7 @@ public final class TelephonyPermissions {
// If we don't have the runtime permission, but do have carrier privileges, that
// suffices for reading phone state.
if (SubscriptionManager.isValidSubscriptionId(subId)) {
- enforceCarrierPrivilege(telephonySupplier, subId, uid, message);
+ enforceCarrierPrivilege(context, subId, uid, message);
return true;
}
throw phoneStateException;
@@ -210,23 +161,16 @@ public final class TelephonyPermissions {
}
/**
- * Check whether the app with the given pid/uid can read phone state, or has carrier
- * privileges on any active subscription.
- *
- * <p>If the app does not have carrier privilege, this method will return {@code false} instead
- * of throwing a SecurityException. Therefore, the callers cannot tell the difference
- * between M+ apps which declare the runtime permission but do not have it, and pre-M apps
- * which declare the static permission but had access revoked via AppOps. Apps in the former
- * category expect SecurityExceptions; apps in the latter don't. So this method is suitable for
- * use only if the behavior in both scenarios is meant to be identical.
- *
- * @return {@code true} if the app can read phone state or has carrier privilege;
- * {@code false} otherwise.
+ * Check whether the calling packages has carrier privileges for the passing subscription.
+ * @return {@code true} if the caller has carrier privileges, {@false} otherwise.
*/
- public static boolean checkReadPhoneStateOnAnyActiveSub(Context context, int pid, int uid,
- String callingPackage, @Nullable String callingFeatureId, String message) {
- return checkReadPhoneStateOnAnyActiveSub(context, TELEPHONY_SUPPLIER, pid, uid,
- callingPackage, callingFeatureId, message);
+ public static boolean checkCarrierPrivilegeForSubId(Context context, int subId) {
+ if (SubscriptionManager.isValidSubscriptionId(subId)
+ && getCarrierPrivilegeStatus(context, subId, Binder.getCallingUid())
+ == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
+ return true;
+ }
+ return false;
}
/**
@@ -243,9 +187,7 @@ public final class TelephonyPermissions {
* @return {@code true} if the app can read phone state or has carrier privilege;
* {@code false} otherwise.
*/
- @VisibleForTesting
- public static boolean checkReadPhoneStateOnAnyActiveSub(
- Context context, Supplier<ITelephony> telephonySupplier, int pid, int uid,
+ public static boolean checkReadPhoneStateOnAnyActiveSub(Context context, int pid, int uid,
String callingPackage, @Nullable String callingFeatureId, String message) {
try {
context.enforcePermission(
@@ -260,7 +202,7 @@ public final class TelephonyPermissions {
} catch (SecurityException phoneStateException) {
// If we don't have the runtime permission, but do have carrier privileges, that
// suffices for reading phone state.
- return checkCarrierPrivilegeForAnySubId(context, telephonySupplier, uid);
+ return checkCarrierPrivilegeForAnySubId(context, uid);
}
}
@@ -375,12 +317,11 @@ public final class TelephonyPermissions {
}
// If the calling package has carrier privileges for specified sub, then allow access.
- if (checkCarrierPrivilegeForSubId(subId)) return true;
+ if (checkCarrierPrivilegeForSubId(context, subId)) return true;
// If the calling package has carrier privileges for any subscription
// and allowCarrierPrivilegeOnAnySub is set true, then allow access.
- if (allowCarrierPrivilegeOnAnySub && checkCarrierPrivilegeForAnySubId(
- context, TELEPHONY_SUPPLIER, uid)) {
+ if (allowCarrierPrivilegeOnAnySub && checkCarrierPrivilegeForAnySubId(context, uid)) {
return true;
}
@@ -468,7 +409,7 @@ public final class TelephonyPermissions {
uid) == PackageManager.PERMISSION_GRANTED) {
return false;
}
- if (checkCarrierPrivilegeForSubId(subId)) {
+ if (checkCarrierPrivilegeForSubId(context, subId)) {
return false;
}
}
@@ -484,26 +425,12 @@ public final class TelephonyPermissions {
public static boolean checkReadCallLog(
Context context, int subId, int pid, int uid, String callingPackage,
@Nullable String callingPackageName) {
- return checkReadCallLog(
- context, TELEPHONY_SUPPLIER, subId, pid, uid, callingPackage, callingPackageName);
- }
-
- /**
- * Check whether the app with the given pid/uid can read the call log.
- * @return {@code true} if the specified app has the read call log permission and AppOpp granted
- * to it, {@code false} otherwise.
- */
- @VisibleForTesting
- public static boolean checkReadCallLog(
- Context context, Supplier<ITelephony> telephonySupplier, int subId, int pid, int uid,
- String callingPackage, @Nullable String callingFeatureId) {
-
if (context.checkPermission(Manifest.permission.READ_CALL_LOG, pid, uid)
!= PERMISSION_GRANTED) {
// If we don't have the runtime permission, but do have carrier privileges, that
// suffices for being able to see the call phone numbers.
if (SubscriptionManager.isValidSubscriptionId(subId)) {
- enforceCarrierPrivilege(telephonySupplier, subId, uid, "readCallLog");
+ enforceCarrierPrivilege(context, subId, uid, "readCallLog");
return true;
}
return false;
@@ -513,7 +440,7 @@ public final class TelephonyPermissions {
// revoked.
AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
return appOps.noteOp(AppOpsManager.OPSTR_READ_CALL_LOG, uid, callingPackage,
- callingFeatureId, null) == AppOpsManager.MODE_ALLOWED;
+ callingPackageName, null) == AppOpsManager.MODE_ALLOWED;
}
/**
@@ -526,7 +453,7 @@ public final class TelephonyPermissions {
Context context, int subId, String callingPackage, @Nullable String callingFeatureId,
String message) {
return checkReadPhoneNumber(
- context, TELEPHONY_SUPPLIER, subId, Binder.getCallingPid(), Binder.getCallingUid(),
+ context, subId, Binder.getCallingPid(), Binder.getCallingUid(),
callingPackage, callingFeatureId, message);
}
@@ -538,7 +465,7 @@ public final class TelephonyPermissions {
*/
@VisibleForTesting
public static boolean checkReadPhoneNumber(
- Context context, Supplier<ITelephony> telephonySupplier, int subId, int pid, int uid,
+ Context context, int subId, int pid, int uid,
String callingPackage, @Nullable String callingFeatureId, String message) {
// Default SMS app can always read it.
AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
@@ -553,7 +480,7 @@ public final class TelephonyPermissions {
// First, check if we can read the phone state.
try {
return checkReadPhoneState(
- context, telephonySupplier, subId, pid, uid, callingPackage, callingFeatureId,
+ context, subId, pid, uid, callingPackage, callingFeatureId,
message);
} catch (SecurityException readPhoneStateSecurityException) {
}
@@ -595,7 +522,7 @@ public final class TelephonyPermissions {
}
if (DBG) Rlog.d(LOG_TAG, "No modify permission, check carrier privilege next.");
- enforceCallingOrSelfCarrierPrivilege(subId, message);
+ enforceCallingOrSelfCarrierPrivilege(context, subId, message);
}
/**
@@ -615,7 +542,7 @@ public final class TelephonyPermissions {
Rlog.d(LOG_TAG, "No READ_PHONE_STATE permission, check carrier privilege next.");
}
- enforceCallingOrSelfCarrierPrivilege(subId, message);
+ enforceCallingOrSelfCarrierPrivilege(context, subId, message);
}
/**
@@ -636,7 +563,7 @@ public final class TelephonyPermissions {
+ "check carrier privilege next.");
}
- enforceCallingOrSelfCarrierPrivilege(subId, message);
+ enforceCallingOrSelfCarrierPrivilege(context, subId, message);
}
/**
@@ -644,21 +571,18 @@ public final class TelephonyPermissions {
*
* @throws SecurityException if the caller does not have the required privileges
*/
- public static void enforceCallingOrSelfCarrierPrivilege(int subId, String message) {
+ public static void enforceCallingOrSelfCarrierPrivilege(
+ Context context, int subId, String message) {
// NOTE: It's critical that we explicitly pass the calling UID here rather than call
// TelephonyManager#hasCarrierPrivileges directly, as the latter only works when called from
// the phone process. When called from another process, it will check whether that process
// has carrier privileges instead.
- enforceCarrierPrivilege(subId, Binder.getCallingUid(), message);
- }
-
- private static void enforceCarrierPrivilege(int subId, int uid, String message) {
- enforceCarrierPrivilege(TELEPHONY_SUPPLIER, subId, uid, message);
+ enforceCarrierPrivilege(context, subId, Binder.getCallingUid(), message);
}
private static void enforceCarrierPrivilege(
- Supplier<ITelephony> telephonySupplier, int subId, int uid, String message) {
- if (getCarrierPrivilegeStatus(telephonySupplier, subId, uid)
+ Context context, int subId, int uid, String message) {
+ if (getCarrierPrivilegeStatus(context, subId, uid)
!= TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
if (DBG) Rlog.e(LOG_TAG, "No Carrier Privilege.");
throw new SecurityException(message);
@@ -666,13 +590,12 @@ public final class TelephonyPermissions {
}
/** Returns whether the provided uid has carrier privileges for any active subscription ID. */
- private static boolean checkCarrierPrivilegeForAnySubId(
- Context context, Supplier<ITelephony> telephonySupplier, int uid) {
+ private static boolean checkCarrierPrivilegeForAnySubId(Context context, int uid) {
SubscriptionManager sm = (SubscriptionManager) context.getSystemService(
Context.TELEPHONY_SUBSCRIPTION_SERVICE);
int[] activeSubIds = sm.getActiveSubscriptionIdList(/* visibleOnly */ false);
for (int activeSubId : activeSubIds) {
- if (getCarrierPrivilegeStatus(telephonySupplier, activeSubId, uid)
+ if (getCarrierPrivilegeStatus(context, activeSubId, uid)
== TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
return true;
}
@@ -680,18 +603,10 @@ public final class TelephonyPermissions {
return false;
}
- private static int getCarrierPrivilegeStatus(
- Supplier<ITelephony> telephonySupplier, int subId, int uid) {
- ITelephony telephony = telephonySupplier.get();
- try {
- if (telephony != null) {
- return telephony.getCarrierPrivilegeStatusForUid(subId, uid);
- }
- } catch (RemoteException e) {
- // Fallback below.
- }
- Rlog.e(LOG_TAG, "Phone process is down, cannot check carrier privileges");
- return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
+ private static int getCarrierPrivilegeStatus(Context context, int subId, int uid) {
+ TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(
+ Context.TELEPHONY_SERVICE);
+ return telephonyManager.createForSubscriptionId(subId).getCarrierPrivilegeStatus(uid);
}
/**
diff --git a/telephony/java/android/telephony/Annotation.java b/telephony/java/android/telephony/Annotation.java
index 73faf9f5f9f4..3940a3b0a1cf 100644
--- a/telephony/java/android/telephony/Annotation.java
+++ b/telephony/java/android/telephony/Annotation.java
@@ -116,7 +116,8 @@ public class Annotation {
ApnSetting.TYPE_CBS,
ApnSetting.TYPE_IA,
ApnSetting.TYPE_EMERGENCY,
- ApnSetting.TYPE_MCX
+ ApnSetting.TYPE_MCX,
+ ApnSetting.TYPE_XCAP,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ApnType {
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index b71bd85b0a34..94085e918bf5 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -210,6 +210,12 @@ public class SubscriptionInfo implements Parcelable {
private int mSubscriptionType;
/**
+ * Whether uicc applications are configured to enable or disable.
+ * By default it's true.
+ */
+ private boolean mAreUiccApplicationsEnabled = true;
+
+ /**
* @hide
*/
public SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName,
@@ -220,7 +226,7 @@ public class SubscriptionInfo implements Parcelable {
roaming, icon, mcc, mnc, countryIso, isEmbedded, nativeAccessRules, cardString, -1,
false, null, false, TelephonyManager.UNKNOWN_CARRIER_ID,
SubscriptionManager.PROFILE_CLASS_DEFAULT,
- SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM, null, null);
+ SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM, null, null, true);
}
/**
@@ -234,7 +240,7 @@ public class SubscriptionInfo implements Parcelable {
this(id, iccId, simSlotIndex, displayName, carrierName, nameSource, iconTint, number,
roaming, icon, mcc, mnc, countryIso, isEmbedded, nativeAccessRules, cardString, -1,
isOpportunistic, groupUUID, false, carrierId, profileClass,
- SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM, null, null);
+ SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM, null, null, true);
}
/**
@@ -246,7 +252,8 @@ public class SubscriptionInfo implements Parcelable {
@Nullable UiccAccessRule[] nativeAccessRules, String cardString, int cardId,
boolean isOpportunistic, @Nullable String groupUUID, boolean isGroupDisabled,
int carrierId, int profileClass, int subType, @Nullable String groupOwner,
- @Nullable UiccAccessRule[] carrierConfigAccessRules) {
+ @Nullable UiccAccessRule[] carrierConfigAccessRules,
+ boolean areUiccApplicationsEnabled) {
this.mId = id;
this.mIccId = iccId;
this.mSimSlotIndex = simSlotIndex;
@@ -272,6 +279,7 @@ public class SubscriptionInfo implements Parcelable {
this.mSubscriptionType = subType;
this.mGroupOwner = groupOwner;
this.mCarrierConfigAccessRules = carrierConfigAccessRules;
+ this.mAreUiccApplicationsEnabled = areUiccApplicationsEnabled;
}
/**
@@ -660,6 +668,15 @@ public class SubscriptionInfo implements Parcelable {
return mIsGroupDisabled;
}
+ /**
+ * Return whether uicc applications are set to be enabled or disabled.
+ * @hide
+ */
+ @SystemApi
+ public boolean areUiccApplicationsEnabled() {
+ return mAreUiccApplicationsEnabled;
+ }
+
public static final @android.annotation.NonNull Parcelable.Creator<SubscriptionInfo> CREATOR = new Parcelable.Creator<SubscriptionInfo>() {
@Override
public SubscriptionInfo createFromParcel(Parcel source) {
@@ -691,12 +708,13 @@ public class SubscriptionInfo implements Parcelable {
String groupOwner = source.readString();
UiccAccessRule[] carrierConfigAccessRules = source.createTypedArray(
UiccAccessRule.CREATOR);
+ boolean areUiccApplicationsEnabled = source.readBoolean();
SubscriptionInfo info = new SubscriptionInfo(id, iccId, simSlotIndex, displayName,
carrierName, nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc,
countryIso, isEmbedded, nativeAccessRules, cardString, cardId, isOpportunistic,
groupUUID, isGroupDisabled, carrierid, profileClass, subType, groupOwner,
- carrierConfigAccessRules);
+ carrierConfigAccessRules, areUiccApplicationsEnabled);
info.setAssociatedPlmns(ehplmns, hplmns);
return info;
}
@@ -736,6 +754,7 @@ public class SubscriptionInfo implements Parcelable {
dest.writeStringArray(mHplmns);
dest.writeString(mGroupOwner);
dest.writeTypedArray(mCarrierConfigAccessRules, flags);
+ dest.writeBoolean(mAreUiccApplicationsEnabled);
}
@Override
@@ -778,15 +797,16 @@ public class SubscriptionInfo implements Parcelable {
+ " hplmns=" + Arrays.toString(mHplmns)
+ " subscriptionType=" + mSubscriptionType
+ " mGroupOwner=" + mGroupOwner
- + " carrierConfigAccessRules=" + mCarrierConfigAccessRules + "}";
+ + " carrierConfigAccessRules=" + mCarrierConfigAccessRules
+ + " mAreUiccApplicationsEnabled=" + mAreUiccApplicationsEnabled + "}";
}
@Override
public int hashCode() {
return Objects.hash(mId, mSimSlotIndex, mNameSource, mIconTint, mDataRoaming, mIsEmbedded,
- mIsOpportunistic, mGroupUUID, mIccId, mNumber, mMcc, mMnc,
- mCountryIso, mCardString, mCardId, mDisplayName, mCarrierName, mNativeAccessRules,
- mIsGroupDisabled, mCarrierId, mProfileClass, mGroupOwner);
+ mIsOpportunistic, mGroupUUID, mIccId, mNumber, mMcc, mMnc, mCountryIso, mCardString,
+ mCardId, mDisplayName, mCarrierName, mNativeAccessRules, mIsGroupDisabled,
+ mCarrierId, mProfileClass, mGroupOwner, mAreUiccApplicationsEnabled);
}
@Override
@@ -809,6 +829,7 @@ public class SubscriptionInfo implements Parcelable {
&& mIsEmbedded == toCompare.mIsEmbedded
&& mIsOpportunistic == toCompare.mIsOpportunistic
&& mIsGroupDisabled == toCompare.mIsGroupDisabled
+ && mAreUiccApplicationsEnabled == toCompare.mAreUiccApplicationsEnabled
&& mCarrierId == toCompare.mCarrierId
&& Objects.equals(mGroupUUID, toCompare.mGroupUUID)
&& Objects.equals(mIccId, toCompare.mIccId)
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index a82ae887224c..740622dae1d9 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -835,6 +835,12 @@ public class SubscriptionManager {
public static final String IMSI = "imsi";
/**
+ * Whether uicc applications is set to be enabled or disabled. By default it's enabled.
+ * @hide
+ */
+ public static final String UICC_APPLICATIONS_ENABLED = "uicc_applications_enabled";
+
+ /**
* Broadcast Action: The user has changed one of the default subs related to
* data, phone calls, or sms</p>
*
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 9f5acb3072cb..5b7ad12feb0b 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -2441,7 +2441,7 @@ public class TelephonyManager {
/*
* When adding a network type to the list below, make sure to add the correct icon to
- * MobileSignalController.mapIconSets().
+ * MobileSignalController.mapIconSets() as well as NETWORK_TYPES
* Do not add negative types.
*/
/** Network type is unknown */
@@ -2489,8 +2489,36 @@ public class TelephonyManager {
/** Current network is NR(New Radio) 5G. */
public static final int NETWORK_TYPE_NR = TelephonyProtoEnums.NETWORK_TYPE_NR; // 20.
- /** Max network type number. Update as new types are added. Don't add negative types. {@hide} */
- public static final int MAX_NETWORK_TYPE = NETWORK_TYPE_NR;
+ private static final @NetworkType int[] NETWORK_TYPES = {
+ NETWORK_TYPE_GPRS,
+ NETWORK_TYPE_EDGE,
+ NETWORK_TYPE_UMTS,
+ NETWORK_TYPE_CDMA,
+ NETWORK_TYPE_EVDO_0,
+ NETWORK_TYPE_EVDO_A,
+ NETWORK_TYPE_1xRTT,
+ NETWORK_TYPE_HSDPA,
+ NETWORK_TYPE_HSUPA,
+ NETWORK_TYPE_HSPA,
+ NETWORK_TYPE_IDEN,
+ NETWORK_TYPE_EVDO_B,
+ NETWORK_TYPE_LTE,
+ NETWORK_TYPE_EHRPD,
+ NETWORK_TYPE_HSPAP,
+ NETWORK_TYPE_GSM,
+ NETWORK_TYPE_TD_SCDMA,
+ NETWORK_TYPE_IWLAN,
+ NETWORK_TYPE_LTE_CA,
+ NETWORK_TYPE_NR
+ };
+
+ /**
+ * Return a collection of all network types
+ * @return network types
+ */
+ public static @NonNull @NetworkType int[] getAllNetworkTypes() {
+ return NETWORK_TYPES;
+ }
/**
* Return the current data network type.
@@ -8358,6 +8386,44 @@ public class TelephonyManager {
}
/**
+ * Shut down all the live radios over all the slot index.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public void shutdownAllRadios() {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ telephony.shutdownMobileRadios();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling ITelephony#shutdownMobileRadios", e);
+ }
+ }
+
+ /**
+ * Check if any radio is on over all the slot indexes.
+ *
+ * @return {@code true} if any radio is on over any slot index.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public boolean isAnyRadioPoweredOn() {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.needMobileRadioShutdown();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling ITelephony#needMobileRadioShutdown", e);
+ }
+ return false;
+ }
+
+ /**
* Radio explicitly powered off (e.g, airplane mode).
* @hide
*/
@@ -11702,6 +11768,32 @@ public class TelephonyManager {
}
/**
+ * Get the calling application status about carrier privileges for the subscription created
+ * in TelephonyManager. Used by Telephony Module for permission checking.
+ *
+ * @param uid Uid to check.
+ * @return any value of {@link #CARRIER_PRIVILEGE_STATUS_HAS_ACCESS},
+ * {@link #CARRIER_PRIVILEGE_STATUS_NO_ACCESS},
+ * {@link #CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED}, or
+ * {@link #CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES}
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public int getCarrierPrivilegeStatus(int uid) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.getCarrierPrivilegeStatusForUid(getSubId(), uid);
+ }
+ } catch (RemoteException ex) {
+ Log.e(TAG, "getCarrierPrivilegeStatus RemoteException", ex);
+ }
+ return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
+ }
+
+ /**
* Return whether data is enabled for certain APN type. This will tell if framework will accept
* corresponding network requests on a subId.
*
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index 60774e7f1e7f..034fc220cbbe 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -20,7 +20,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ContentValues;
import android.database.Cursor;
-import android.hardware.radio.V1_4.ApnTypes;
+import android.hardware.radio.V1_5.ApnTypes;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
@@ -110,6 +110,8 @@ public class ApnSetting implements Parcelable {
public static final int TYPE_EMERGENCY = ApnTypes.EMERGENCY;
/** APN type for MCX (Mission Critical Service) where X can be PTT/Video/Data */
public static final int TYPE_MCX = ApnTypes.MCX;
+ /** APN type for XCAP. */
+ public static final int TYPE_XCAP = ApnTypes.XCAP;
// Possible values for authentication types.
/** No authentication type. */
@@ -198,6 +200,7 @@ public class ApnSetting implements Parcelable {
APN_TYPE_STRING_MAP.put("ia", TYPE_IA);
APN_TYPE_STRING_MAP.put("emergency", TYPE_EMERGENCY);
APN_TYPE_STRING_MAP.put("mcx", TYPE_MCX);
+ APN_TYPE_STRING_MAP.put("xcap", TYPE_XCAP);
APN_TYPE_INT_MAP = new ArrayMap<Integer, String>();
APN_TYPE_INT_MAP.put(TYPE_DEFAULT, "default");
APN_TYPE_INT_MAP.put(TYPE_MMS, "mms");
@@ -210,6 +213,7 @@ public class ApnSetting implements Parcelable {
APN_TYPE_INT_MAP.put(TYPE_IA, "ia");
APN_TYPE_INT_MAP.put(TYPE_EMERGENCY, "emergency");
APN_TYPE_INT_MAP.put(TYPE_MCX, "mcx");
+ APN_TYPE_INT_MAP.put(TYPE_XCAP, "xcap");
PROTOCOL_STRING_MAP = new ArrayMap<String, Integer>();
PROTOCOL_STRING_MAP.put("IP", PROTOCOL_IP);
@@ -1944,8 +1948,9 @@ public class ApnSetting implements Parcelable {
* {@link ApnSetting} built from this builder otherwise.
*/
public ApnSetting build() {
- if ((mApnTypeBitmask & (TYPE_DEFAULT | TYPE_MMS | TYPE_SUPL | TYPE_DUN | TYPE_HIPRI |
- TYPE_FOTA | TYPE_IMS | TYPE_CBS | TYPE_IA | TYPE_EMERGENCY | TYPE_MCX)) == 0
+ if ((mApnTypeBitmask & (TYPE_DEFAULT | TYPE_MMS | TYPE_SUPL | TYPE_DUN | TYPE_HIPRI
+ | TYPE_FOTA | TYPE_IMS | TYPE_CBS | TYPE_IA | TYPE_EMERGENCY | TYPE_MCX
+ | TYPE_XCAP)) == 0
|| TextUtils.isEmpty(mApnName) || TextUtils.isEmpty(mEntryName)) {
return null;
}
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index aad7f3e7bf2a..fde2c5a9a738 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -154,6 +154,8 @@ public class PhoneConstants {
public static final String APN_TYPE_EMERGENCY = "emergency";
/** APN type for Mission Critical Services */
public static final String APN_TYPE_MCX = "mcx";
+ /** APN type for XCAP */
+ public static final String APN_TYPE_XCAP = "xcap";
/** Array of all APN types */
public static final String[] APN_TYPES = {APN_TYPE_DEFAULT,
APN_TYPE_MMS,
@@ -165,7 +167,8 @@ public class PhoneConstants {
APN_TYPE_CBS,
APN_TYPE_IA,
APN_TYPE_EMERGENCY,
- APN_TYPE_MCX
+ APN_TYPE_MCX,
+ APN_TYPE_XCAP,
};
public static final int RIL_CARD_MAX_APPS = 8;
diff --git a/tests/ApkVerityTest/Android.bp b/tests/ApkVerityTest/Android.bp
index 9bb9983f66a9..c8d1ce1e7837 100644
--- a/tests/ApkVerityTest/Android.bp
+++ b/tests/ApkVerityTest/Android.bp
@@ -19,14 +19,14 @@ java_test_host {
test_suites: ["general-tests"],
target_required: [
"block_device_writer_module",
- "ApkVerityTestApp",
- "ApkVerityTestAppSplit",
],
data: [
":ApkVerityTestCertDer",
+ ":ApkVerityTestApp",
":ApkVerityTestAppFsvSig",
":ApkVerityTestAppDm",
":ApkVerityTestAppDmFsvSig",
+ ":ApkVerityTestAppSplit",
":ApkVerityTestAppSplitFsvSig",
":ApkVerityTestAppSplitDm",
":ApkVerityTestAppSplitDmFsvSig",
diff --git a/tests/ManagedProfileLifecycleStressTest/app/DummyDPC/Android.bp b/tests/ManagedProfileLifecycleStressTest/app/DummyDPC/Android.bp
index d95af340337e..1f47b03d0074 100644
--- a/tests/ManagedProfileLifecycleStressTest/app/DummyDPC/Android.bp
+++ b/tests/ManagedProfileLifecycleStressTest/app/DummyDPC/Android.bp
@@ -17,4 +17,5 @@ android_test {
defaults: ["cts_defaults"],
srcs: ["src/**/*.java"],
sdk_version: "current",
+ test_suites: ["device-tests"],
}
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index b52880e29e30..46efdd6f6aeb 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -186,7 +186,7 @@ interface IWifiManager
byte[] retrieveSoftApBackupData();
- void restoreSoftApBackupData(in byte[] data);
+ SoftApConfiguration restoreSoftApBackupData(in byte[] data);
void restoreSupplicantBackupData(in byte[] supplicantData, in byte[] ipConfigData);
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 50d62a0b627e..3bcad2f87583 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -4686,10 +4686,13 @@ public class WifiManager {
}
/**
- * Retrieve the soft ap config data to be backed to save current config data.
+ * Returns a byte stream representing the data that needs to be backed up to save the
+ * current soft ap config data.
+ *
+ * This soft ap config can be restored by calling {@link #restoreSoftApBackupData(byte[])}
* @hide
*/
- @Nullable
+ @NonNull
@SystemApi
@RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
public byte[] retrieveSoftApBackupData() {
@@ -4701,15 +4704,17 @@ public class WifiManager {
}
/**
- * Restore soft ap config from the backed up data.
+ * Returns soft ap config from the backed up data.
+ * @param data byte stream in the same format produced by {@link #retrieveSoftApBackupData()}
+ *
* @hide
*/
@Nullable
@SystemApi
@RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
- public void restoreSoftApBackupData(@NonNull byte[] data) {
+ public SoftApConfiguration restoreSoftApBackupData(@NonNull byte[] data) {
try {
- mService.restoreSoftApBackupData(data);
+ return mService.restoreSoftApBackupData(data);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/wifi/java/com/android/server/wifi/BaseWifiService.java b/wifi/java/com/android/server/wifi/BaseWifiService.java
index 524a53c03305..86392fa1b047 100644
--- a/wifi/java/com/android/server/wifi/BaseWifiService.java
+++ b/wifi/java/com/android/server/wifi/BaseWifiService.java
@@ -28,7 +28,6 @@ import android.net.wifi.INetworkRequestMatchCallback;
import android.net.wifi.IOnWifiActivityEnergyInfoListener;
import android.net.wifi.IOnWifiUsabilityStatsListener;
import android.net.wifi.IScanResultsCallback;
-import android.net.wifi.IScanResultsListener;
import android.net.wifi.ISoftApCallback;
import android.net.wifi.ISuggestionConnectionStatusListener;
import android.net.wifi.ITrafficStateCallback;
@@ -414,7 +413,7 @@ public class BaseWifiService extends IWifiManager.Stub {
}
@Override
- public void restoreSoftApBackupData(byte[] data) {
+ public SoftApConfiguration restoreSoftApBackupData(byte[] data) {
throw new UnsupportedOperationException();
}