Merge "Remove settings and resources about CarrierNetworkNotifier"
diff --git a/Android.bp b/Android.bp
index 190e80d..9d05ffd 100644
--- a/Android.bp
+++ b/Android.bp
@@ -25,30 +25,110 @@
//
// READ ME: ########################################################
+filegroup {
+ name: "framework-defaults-java-srcs",
+ srcs: [
+ // java sources under this directory
+ "core/java/**/*.java",
+ "drm/java/**/*.java",
+ "graphics/java/**/*.java",
+ "keystore/java/**/*.java",
+ "location/java/**/*.java",
+ "lowpan/java/**/*.java",
+ "media/java/**/*.java",
+ "media/mca/effect/java/**/*.java",
+ "media/mca/filterfw/java/**/*.java",
+ "media/mca/filterpacks/java/**/*.java",
+ "opengl/java/**/*.java",
+ "rs/java/**/*.java",
+ "sax/java/**/*.java",
+ "telecomm/java/**/*.java",
+ "telephony/java/**/*.java",
+ "wifi/java/**/*.java",
+ ],
+}
+
+// TODO(b/70046217): make these as filegroups where the base directory for aidl files
+// is given as 'path'. Eliminate the need for aidl_local_include_dirs.
+framework_srcs = [
+ // aidl under this directory
+ // b/70046217#comment15 These MUST come after all java srcs.
+ // TODO(b/70046217) remove the above requirement
+ "core/java/**/*.aidl",
+ "graphics/java/**/*.aidl",
+ "keystore/java/**/*.aidl",
+ "location/java/**/*.aidl",
+ "lowpan/java/**/*.aidl",
+ "media/java/**/*.aidl",
+ "packages/services/PacProcessor/**/*.aidl",
+ "packages/services/Proxy/**/*.aidl",
+ "telecomm/java/**/*.aidl",
+ "telephony/java/**/*.aidl",
+ "wifi/java/**/*.aidl",
+
+ // aidl from external directories
+ ":dumpstate_aidl",
+ ":gatekeeper_aidl",
+ ":gsiservice_aidl",
+ ":incidentcompanion_aidl",
+ ":installd_aidl",
+ ":keystore_aidl",
+ ":libaudioclient_aidl",
+ ":libbinder_aidl",
+ ":libbluetooth-binder-aidl",
+ ":libcamera_client_aidl",
+ ":libcamera_client_framework_aidl",
+ ":libupdate_engine_aidl",
+ ":storaged_aidl",
+ ":vold_aidl",
+
+ // etc.
+ "core/java/**/*.logtags",
+ ":framework-javastream-protos",
+ ":framework-statslog-gen",
+]
+
+framework_aidl_local_include_dirs = [
+ "core/java",
+ "drm/java",
+ "graphics/java",
+ "keystore/java",
+ "location/java",
+ "lowpan/java",
+ "media/java",
+ "media/apex/java",
+ "media/mca/effect/java",
+ "media/mca/filterfw/java",
+ "media/mca/filterpacks/java",
+ "opengl/java",
+ "rs/java",
+ "sax/java",
+ "telecomm/java",
+ "telephony/java",
+ "wifi/java",
+]
+
+framework_aidl_external_include_dirs = [
+ "frameworks/av/camera/aidl",
+ "frameworks/av/media/libaudioclient/aidl",
+ "frameworks/native/aidl/binder",
+ "frameworks/native/aidl/gui",
+ "frameworks/native/cmds/dumpstate/binder",
+ "frameworks/native/libs/incidentcompanion/binder",
+ "system/bt/binder",
+ "system/core/gatekeeperd/binder",
+ "system/core/storaged/binder",
+ "system/gsid/aidl",
+ "system/security/keystore/binder",
+ "system/update_engine/binder_bindings",
+ "system/vold/binder",
+]
+
java_defaults {
name: "framework-aidl-export-defaults",
aidl: {
- export_include_dirs: [
- // From build/make/core/pathmap.mk FRAMEWORK_BASE_SUBDIRS
- "core/java",
- "graphics/java",
- "location/java",
- "lowpan/java",
- "media/java",
- "media/apex/java",
- "media/mca/effect/java",
- "media/mca/filterfw/java",
- "media/mca/filterpacks/java",
- "drm/java",
- "opengl/java",
- "sax/java",
- "telecomm/java",
- "telephony/java",
- "wifi/java",
- "keystore/java",
- "rs/java",
- ],
+ export_include_dirs: framework_aidl_local_include_dirs,
},
}
@@ -58,689 +138,12 @@
installable: true,
srcs: [
- // From build/make/core/pathmap.mk FRAMEWORK_BASE_SUBDIRS
- "core/java/**/*.java",
- "graphics/java/**/*.java",
- "location/java/**/*.java",
- "lowpan/java/**/*.java",
- "media/java/**/*.java",
- "media/mca/effect/java/**/*.java",
- "media/mca/filterfw/java/**/*.java",
- "media/mca/filterpacks/java/**/*.java",
- "drm/java/**/*.java",
- "opengl/java/**/*.java",
- "sax/java/**/*.java",
- "telecomm/java/**/*.java",
- "telephony/java/**/*.java",
- "wifi/java/**/*.java",
- "keystore/java/**/*.java",
- "rs/java/**/*.java",
-
- ":framework-javastream-protos",
-
- "core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl",
- "core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl",
- "core/java/android/accounts/IAccountManager.aidl",
- "core/java/android/accounts/IAccountManagerResponse.aidl",
- "core/java/android/accounts/IAccountAuthenticator.aidl",
- "core/java/android/accounts/IAccountAuthenticatorResponse.aidl",
- "core/java/android/app/IActivityController.aidl",
- "core/java/android/app/IActivityManager.aidl",
- "core/java/android/app/IActivityPendingResult.aidl",
- "core/java/android/app/IActivityTaskManager.aidl",
- "core/java/android/app/IAlarmCompleteListener.aidl",
- "core/java/android/app/IAlarmListener.aidl",
- "core/java/android/app/IAlarmManager.aidl",
- "core/java/android/app/IAppTask.aidl",
- "core/java/android/app/IApplicationThread.aidl",
- "core/java/android/app/IAssistDataReceiver.aidl",
- "core/java/android/app/ITaskStackListener.aidl",
- "core/java/android/app/IBackupAgent.aidl",
- "core/java/android/app/IEphemeralResolver.aidl",
- "core/java/android/app/IInstantAppResolver.aidl",
- "core/java/android/app/IInstrumentationWatcher.aidl",
- "core/java/android/app/INotificationManager.aidl",
- "core/java/android/app/IProcessObserver.aidl",
- "core/java/android/app/IRequestFinishCallback.aidl",
- "core/java/android/app/ISearchManager.aidl",
- "core/java/android/app/ISearchManagerCallback.aidl",
- "core/java/android/app/IServiceConnection.aidl",
- "core/java/android/app/IStopUserCallback.aidl",
- "core/java/android/app/ITransientNotification.aidl",
- "core/java/android/app/IUidObserver.aidl",
- "core/java/android/app/IUiAutomationConnection.aidl",
- "core/java/android/app/IUiModeManager.aidl",
- "core/java/android/app/IUriGrantsManager.aidl",
- "core/java/android/app/IUserSwitchObserver.aidl",
- "core/java/android/app/IWallpaperManager.aidl",
- "core/java/android/app/IWallpaperManagerCallback.aidl",
- "core/java/android/app/admin/IDeviceAdminService.aidl",
- "core/java/android/app/admin/IDevicePolicyManager.aidl",
- "core/java/android/app/admin/StartInstallingUpdateCallback.aidl",
- "core/java/android/app/trust/IStrongAuthTracker.aidl",
- "core/java/android/app/trust/ITrustManager.aidl",
- "core/java/android/app/trust/ITrustListener.aidl",
- "core/java/android/app/backup/IBackupCallback.aidl",
- "core/java/android/app/backup/IBackupManager.aidl",
- "core/java/android/app/backup/IBackupObserver.aidl",
- "core/java/android/app/backup/IBackupManagerMonitor.aidl",
- "core/java/android/app/backup/IFullBackupRestoreObserver.aidl",
- "core/java/android/app/backup/IRestoreObserver.aidl",
- "core/java/android/app/backup/IRestoreSession.aidl",
- "core/java/android/app/backup/ISelectBackupTransportCallback.aidl",
- "core/java/android/app/contentsuggestions/IClassificationsCallback.aidl",
- "core/java/android/app/contentsuggestions/IContentSuggestionsManager.aidl",
- "core/java/android/app/contentsuggestions/ISelectionsCallback.aidl",
- "core/java/android/app/prediction/IPredictionCallback.aidl",
- "core/java/android/app/prediction/IPredictionManager.aidl",
- "core/java/android/app/role/IOnRoleHoldersChangedListener.aidl",
- "core/java/android/app/role/IRoleController.aidl",
- "core/java/android/app/role/IRoleManager.aidl",
- "core/java/android/app/slice/ISliceManager.aidl",
- "core/java/android/app/slice/ISliceListener.aidl",
- "core/java/android/app/timedetector/ITimeDetectorService.aidl",
- "core/java/android/app/timezone/ICallback.aidl",
- "core/java/android/app/timezone/IRulesManager.aidl",
- "core/java/android/app/usage/ICacheQuotaService.aidl",
- "core/java/android/app/usage/IStorageStatsManager.aidl",
- "core/java/android/app/usage/IUsageStatsManager.aidl",
- ":libbluetooth-binder-aidl",
- "core/java/android/content/IClipboard.aidl",
- "core/java/android/content/IContentService.aidl",
- "core/java/android/content/IIntentReceiver.aidl",
- "core/java/android/content/IIntentSender.aidl",
- "core/java/android/content/IOnPrimaryClipChangedListener.aidl",
- "core/java/android/content/IRestrictionsManager.aidl",
- "core/java/android/content/ISyncAdapter.aidl",
- "core/java/android/content/ISyncAdapterUnsyncableAccountCallback.aidl",
- "core/java/android/content/ISyncContext.aidl",
- "core/java/android/content/ISyncServiceAdapter.aidl",
- "core/java/android/content/ISyncStatusObserver.aidl",
- "core/java/android/content/om/IOverlayManager.aidl",
- "core/java/android/content/pm/ICrossProfileApps.aidl",
- "core/java/android/content/pm/IDexModuleRegisterCallback.aidl",
- "core/java/android/content/pm/ILauncherApps.aidl",
- "core/java/android/content/pm/IOnAppsChangedListener.aidl",
- "core/java/android/content/pm/IOtaDexopt.aidl",
- "core/java/android/content/pm/IPackageDataObserver.aidl",
- "core/java/android/content/pm/IPackageDeleteObserver.aidl",
- "core/java/android/content/pm/IPackageDeleteObserver2.aidl",
- "core/java/android/content/pm/IPackageInstallObserver2.aidl",
- "core/java/android/content/pm/IPackageInstaller.aidl",
- "core/java/android/content/pm/IPackageInstallerCallback.aidl",
- "core/java/android/content/pm/IPackageInstallerSession.aidl",
- "core/java/android/content/pm/IPackageManager.aidl",
- ":libbinder_aidl",
- "core/java/android/content/pm/IPackageMoveObserver.aidl",
- "core/java/android/content/pm/IPackageStatsObserver.aidl",
- "core/java/android/content/pm/IPinItemRequest.aidl",
- "core/java/android/content/pm/IShortcutService.aidl",
- "core/java/android/content/pm/dex/IArtManager.aidl",
- "core/java/android/content/pm/dex/ISnapshotRuntimeProfileCallback.aidl",
- "core/java/android/content/pm/permission/IRuntimePermissionPresenter.aidl",
- "core/java/android/content/rollback/IRollbackManager.aidl",
- "core/java/android/database/IContentObserver.aidl",
- "core/java/android/debug/IAdbManager.aidl",
- "core/java/android/debug/IAdbTransport.aidl",
- ":libcamera_client_aidl",
- ":libcamera_client_framework_aidl",
- "core/java/android/hardware/IConsumerIrService.aidl",
- "core/java/android/hardware/ISerialManager.aidl",
- "core/java/android/hardware/biometrics/IBiometricConfirmDeviceCredentialCallback.aidl",
- "core/java/android/hardware/biometrics/IBiometricEnabledOnKeyguardCallback.aidl",
- "core/java/android/hardware/biometrics/IBiometricService.aidl",
- "core/java/android/hardware/biometrics/IBiometricServiceReceiver.aidl",
- "core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl",
- "core/java/android/hardware/biometrics/IBiometricServiceLockoutResetCallback.aidl",
- "core/java/android/hardware/display/IColorDisplayManager.aidl",
- "core/java/android/hardware/display/IDisplayManager.aidl",
- "core/java/android/hardware/display/IDisplayManagerCallback.aidl",
- "core/java/android/hardware/display/IVirtualDisplayCallback.aidl",
- "core/java/android/hardware/fingerprint/IFingerprintClientActiveCallback.aidl",
- "core/java/android/hardware/face/IFaceService.aidl",
- "core/java/android/hardware/face/IFaceServiceReceiver.aidl",
- "core/java/android/hardware/fingerprint/IFingerprintService.aidl",
- "core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl",
- "core/java/android/hardware/hdmi/IHdmiControlCallback.aidl",
- "core/java/android/hardware/hdmi/IHdmiControlService.aidl",
- "core/java/android/hardware/hdmi/IHdmiDeviceEventListener.aidl",
- "core/java/android/hardware/hdmi/IHdmiHotplugEventListener.aidl",
- "core/java/android/hardware/hdmi/IHdmiInputChangeListener.aidl",
- "core/java/android/hardware/hdmi/IHdmiMhlVendorCommandListener.aidl",
- "core/java/android/hardware/hdmi/IHdmiRecordListener.aidl",
- "core/java/android/hardware/hdmi/IHdmiSystemAudioModeChangeListener.aidl",
- "core/java/android/hardware/hdmi/IHdmiVendorCommandListener.aidl",
- "core/java/android/hardware/input/IInputManager.aidl",
- "core/java/android/hardware/input/IInputDevicesChangedListener.aidl",
- "core/java/android/hardware/input/ITabletModeChangedListener.aidl",
- "core/java/android/hardware/iris/IIrisService.aidl",
- "core/java/android/hardware/location/IActivityRecognitionHardware.aidl",
- "core/java/android/hardware/location/IActivityRecognitionHardwareClient.aidl",
- "core/java/android/hardware/location/IActivityRecognitionHardwareSink.aidl",
- "core/java/android/hardware/location/IActivityRecognitionHardwareWatcher.aidl",
- "core/java/android/hardware/location/IGeofenceHardware.aidl",
- "core/java/android/hardware/location/IGeofenceHardwareCallback.aidl",
- "core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl",
- "core/java/android/hardware/location/IContextHubCallback.aidl",
- "core/java/android/hardware/location/IContextHubClient.aidl",
- "core/java/android/hardware/location/IContextHubClientCallback.aidl",
- "core/java/android/hardware/location/IContextHubService.aidl",
- "core/java/android/hardware/location/IContextHubTransactionCallback.aidl",
- "core/java/android/hardware/radio/IAnnouncementListener.aidl",
- "core/java/android/hardware/radio/ICloseHandle.aidl",
- "core/java/android/hardware/radio/IRadioService.aidl",
- "core/java/android/hardware/radio/ITuner.aidl",
- "core/java/android/hardware/radio/ITunerCallback.aidl",
- "core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl",
- "core/java/android/hardware/usb/IUsbManager.aidl",
- "core/java/android/hardware/usb/IUsbSerialReader.aidl",
- "core/java/android/net/ICaptivePortal.aidl",
- "core/java/android/net/IConnectivityManager.aidl",
- "core/java/android/hardware/ISensorPrivacyListener.aidl",
- "core/java/android/hardware/ISensorPrivacyManager.aidl",
- "core/java/android/net/IIpConnectivityMetrics.aidl",
- "core/java/android/net/IEthernetManager.aidl",
- "core/java/android/net/IEthernetServiceListener.aidl",
- "core/java/android/net/INetdEventCallback.aidl",
- "core/java/android/net/IIpSecService.aidl",
- "core/java/android/net/INetworkManagementEventObserver.aidl",
- "core/java/android/net/INetworkPolicyListener.aidl",
- "core/java/android/net/INetworkPolicyManager.aidl",
- "core/java/android/net/INetworkRecommendationProvider.aidl",
- "core/java/android/net/INetworkScoreCache.aidl",
- "core/java/android/net/INetworkScoreService.aidl",
- "core/java/android/net/INetworkStatsService.aidl",
- "core/java/android/net/INetworkStatsSession.aidl",
- "core/java/android/net/ISocketKeepaliveCallback.aidl",
- "core/java/android/net/ITestNetworkManager.aidl",
- "core/java/android/net/ITetheringEventCallback.aidl",
- "core/java/android/net/ITetheringStatsProvider.aidl",
- "core/java/android/net/nsd/INsdManager.aidl",
- "core/java/android/nfc/IAppCallback.aidl",
- "core/java/android/nfc/INfcAdapter.aidl",
- "core/java/android/nfc/INfcAdapterExtras.aidl",
- "core/java/android/nfc/INfcTag.aidl",
- "core/java/android/nfc/INfcCardEmulation.aidl",
- "core/java/android/nfc/INfcFCardEmulation.aidl",
- "core/java/android/nfc/INfcUnlockHandler.aidl",
- "core/java/android/nfc/INfcDta.aidl",
- "core/java/android/nfc/ITagRemovedCallback.aidl",
- "core/java/android/se/omapi/ISecureElementService.aidl",
- "core/java/android/se/omapi/ISecureElementListener.aidl",
- "core/java/android/se/omapi/ISecureElementChannel.aidl",
- "core/java/android/se/omapi/ISecureElementReader.aidl",
- "core/java/android/se/omapi/ISecureElementSession.aidl",
- "core/java/android/os/IBatteryPropertiesRegistrar.aidl",
- "core/java/android/os/ICancellationSignal.aidl",
- "core/java/android/os/IDeviceIdentifiersPolicyService.aidl",
- "core/java/android/os/IDeviceIdleController.aidl",
- "core/java/android/os/IHardwarePropertiesManager.aidl",
- ":libincident_aidl",
- "core/java/android/os/IMaintenanceActivityListener.aidl",
- "core/java/android/os/IMessenger.aidl",
- "core/java/android/os/INetworkActivityListener.aidl",
- "core/java/android/os/INetworkManagementService.aidl",
- "core/java/android/os/IPermissionController.aidl",
- "core/java/android/os/IProcessInfoService.aidl",
- "core/java/android/os/IProgressListener.aidl",
- "core/java/android/os/IPowerManager.aidl",
- "core/java/android/os/IRecoverySystem.aidl",
- "core/java/android/os/IRecoverySystemProgressListener.aidl",
- "core/java/android/os/IRemoteCallback.aidl",
- "core/java/android/os/ISchedulingPolicyService.aidl",
- ":statsd_aidl",
- "core/java/android/os/ISystemUpdateManager.aidl",
- "core/java/android/os/IThermalEventListener.aidl",
- "core/java/android/os/IThermalStatusListener.aidl",
- "core/java/android/os/IThermalService.aidl",
- "core/java/android/os/IUpdateLock.aidl",
- "core/java/android/os/IUserManager.aidl",
- ":libvibrator_aidl",
- "core/java/android/os/IVibratorService.aidl",
- "core/java/android/os/image/IDynamicSystemService.aidl",
- "core/java/android/os/storage/IStorageManager.aidl",
- "core/java/android/os/storage/IStorageEventListener.aidl",
- "core/java/android/os/storage/IStorageShutdownObserver.aidl",
- "core/java/android/os/storage/IObbActionListener.aidl",
- "core/java/android/permission/IOnPermissionsChangeListener.aidl",
- "core/java/android/permission/IPermissionController.aidl",
- "core/java/android/permission/IPermissionManager.aidl",
- ":keystore_aidl",
- "core/java/android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl",
- "core/java/android/service/appprediction/IPredictionService.aidl",
- "core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl",
- "core/java/android/service/autofill/augmented/IFillCallback.aidl",
- "core/java/android/service/autofill/IAutoFillService.aidl",
- "core/java/android/service/autofill/IAutofillFieldClassificationService.aidl",
- "core/java/android/service/autofill/IFillCallback.aidl",
- "core/java/android/service/autofill/ISaveCallback.aidl",
- "core/java/android/service/carrier/ICarrierService.aidl",
- "core/java/android/service/carrier/ICarrierMessagingCallback.aidl",
- "core/java/android/service/carrier/ICarrierMessagingService.aidl",
- "core/java/android/service/carrier/ICarrierMessagingClientService.aidl",
- "core/java/android/service/contentsuggestions/IContentSuggestionsService.aidl",
- "core/java/android/service/euicc/IDeleteSubscriptionCallback.aidl",
- "core/java/android/service/euicc/IDownloadSubscriptionCallback.aidl",
- "core/java/android/service/euicc/IEraseSubscriptionsCallback.aidl",
- "core/java/android/service/euicc/IEuiccService.aidl",
- "core/java/android/service/euicc/IGetDefaultDownloadableSubscriptionListCallback.aidl",
- "core/java/android/service/euicc/IGetDownloadableSubscriptionMetadataCallback.aidl",
- "core/java/android/service/euicc/IGetEidCallback.aidl",
- "core/java/android/service/euicc/IGetEuiccInfoCallback.aidl",
- "core/java/android/service/euicc/IGetEuiccProfileInfoListCallback.aidl",
- "core/java/android/service/euicc/IGetOtaStatusCallback.aidl",
- "core/java/android/service/euicc/IOtaStatusChangedCallback.aidl",
- "core/java/android/service/euicc/IRetainSubscriptionsForFactoryResetCallback.aidl",
- "core/java/android/service/euicc/ISwitchToSubscriptionCallback.aidl",
- "core/java/android/service/euicc/IUpdateSubscriptionNicknameCallback.aidl",
- ":gatekeeper_aidl",
- "core/java/android/service/contentcapture/IContentCaptureService.aidl",
- "core/java/android/service/contentcapture/IContentCaptureServiceCallback.aidl",
- "core/java/android/service/notification/INotificationListener.aidl",
- "core/java/android/service/notification/IStatusBarNotificationHolder.aidl",
- "core/java/android/service/notification/IConditionListener.aidl",
- "core/java/android/service/notification/IConditionProvider.aidl",
- "core/java/android/service/settings/suggestions/ISuggestionService.aidl",
- "core/java/android/service/sms/IFinancialSmsService.aidl",
- "core/java/android/service/vr/IPersistentVrStateCallbacks.aidl",
- "core/java/android/service/vr/IVrListener.aidl",
- "core/java/android/service/vr/IVrManager.aidl",
- "core/java/android/service/vr/IVrStateCallbacks.aidl",
- "core/java/android/service/watchdog/IExplicitHealthCheckService.aidl",
- "core/java/android/service/watchdog/PackageConfig.aidl",
- "core/java/android/print/ILayoutResultCallback.aidl",
- "core/java/android/print/IPrinterDiscoveryObserver.aidl",
- "core/java/android/print/IPrintDocumentAdapter.aidl",
- "core/java/android/print/IPrintDocumentAdapterObserver.aidl",
- "core/java/android/print/IPrintJobStateChangeListener.aidl",
- "core/java/android/print/IPrintServicesChangeListener.aidl",
- "core/java/android/printservice/recommendation/IRecommendationsChangeListener.aidl",
- "core/java/android/print/IPrintManager.aidl",
- "core/java/android/print/IPrintSpooler.aidl",
- "core/java/android/print/IPrintSpoolerCallbacks.aidl",
- "core/java/android/print/IPrintSpoolerClient.aidl",
- "core/java/android/printservice/recommendation/IRecommendationServiceCallbacks.aidl",
- "core/java/android/printservice/recommendation/IRecommendationService.aidl",
- "core/java/android/print/IWriteResultCallback.aidl",
- "core/java/android/printservice/IPrintService.aidl",
- "core/java/android/printservice/IPrintServiceClient.aidl",
- "core/java/android/companion/ICompanionDeviceManager.aidl",
- "core/java/android/companion/ICompanionDeviceDiscoveryService.aidl",
- "core/java/android/companion/ICompanionDeviceDiscoveryServiceCallback.aidl",
- "core/java/android/companion/IFindDeviceCallback.aidl",
- "core/java/android/service/dreams/IDreamManager.aidl",
- "core/java/android/service/dreams/IDreamService.aidl",
- "core/java/android/service/oemlock/IOemLockService.aidl",
- "core/java/android/service/persistentdata/IPersistentDataBlockService.aidl",
- "core/java/android/service/trust/ITrustAgentService.aidl",
- "core/java/android/service/trust/ITrustAgentServiceCallback.aidl",
- "core/java/android/service/voice/IVoiceInteractionService.aidl",
- "core/java/android/service/voice/IVoiceInteractionSession.aidl",
- "core/java/android/service/voice/IVoiceInteractionSessionService.aidl",
- "core/java/android/service/wallpaper/IWallpaperConnection.aidl",
- "core/java/android/service/wallpaper/IWallpaperEngine.aidl",
- "core/java/android/service/wallpaper/IWallpaperService.aidl",
- "core/java/android/service/chooser/IChooserTargetService.aidl",
- "core/java/android/service/chooser/IChooserTargetResult.aidl",
- "core/java/android/service/resolver/IResolverRankerService.aidl",
- "core/java/android/service/resolver/IResolverRankerResult.aidl",
- "core/java/android/service/textclassifier/ITextClassifierCallback.aidl",
- "core/java/android/service/textclassifier/ITextClassifierService.aidl",
- "core/java/android/service/attention/IAttentionService.aidl",
- "core/java/android/service/attention/IAttentionCallback.aidl",
- "core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl",
- "core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl",
- "core/java/android/view/accessibility/IAccessibilityManager.aidl",
- "core/java/android/view/accessibility/IAccessibilityManagerClient.aidl",
- "core/java/android/view/autofill/IAutoFillManager.aidl",
- "core/java/android/view/autofill/IAutoFillManagerClient.aidl",
- "core/java/android/view/autofill/IAugmentedAutofillManagerClient.aidl",
- "core/java/android/view/autofill/IAutofillWindowPresenter.aidl",
- "core/java/android/view/contentcapture/IContentCaptureDirectManager.aidl",
- "core/java/android/view/contentcapture/IContentCaptureManager.aidl",
- "core/java/android/view/IApplicationToken.aidl",
- "core/java/android/view/IAppTransitionAnimationSpecsFuture.aidl",
- "core/java/android/view/IDockedStackListener.aidl",
- "core/java/android/view/IDisplayFoldListener.aidl",
- "core/java/android/view/IGraphicsStats.aidl",
- "core/java/android/view/IGraphicsStatsCallback.aidl",
- "core/java/android/view/IInputMonitorHost.aidl",
- "core/java/android/view/IInputFilter.aidl",
- "core/java/android/view/IInputFilterHost.aidl",
- "core/java/android/view/IOnKeyguardExitResult.aidl",
- "core/java/android/view/IPinnedStackController.aidl",
- "core/java/android/view/IPinnedStackListener.aidl",
- "core/java/android/view/IRemoteAnimationRunner.aidl",
- "core/java/android/view/IRecentsAnimationController.aidl",
- "core/java/android/view/IRecentsAnimationRunner.aidl",
- "core/java/android/view/IRemoteAnimationFinishedCallback.aidl",
- "core/java/android/view/IRotationWatcher.aidl",
- "core/java/android/view/ISystemGestureExclusionListener.aidl",
- "core/java/android/view/IWallpaperVisibilityListener.aidl",
- "core/java/android/view/IWindow.aidl",
- "core/java/android/view/IWindowFocusObserver.aidl",
- "core/java/android/view/IWindowId.aidl",
- "core/java/android/view/IWindowManager.aidl",
- "core/java/android/view/IWindowSession.aidl",
- "core/java/android/view/IWindowSessionCallback.aidl",
- "core/java/android/webkit/IWebViewUpdateService.aidl",
- "core/java/android/speech/IRecognitionListener.aidl",
- "core/java/android/speech/IRecognitionService.aidl",
- "core/java/android/speech/tts/ITextToSpeechCallback.aidl",
- "core/java/android/speech/tts/ITextToSpeechService.aidl",
- "core/java/com/android/internal/app/IAppOpsActiveCallback.aidl",
- "core/java/com/android/internal/app/IAppOpsCallback.aidl",
- "core/java/com/android/internal/app/IAppOpsNotedCallback.aidl",
- "core/java/com/android/internal/app/IAppOpsService.aidl",
- "core/java/com/android/internal/app/IBatteryStats.aidl",
- "core/java/com/android/internal/app/ISoundTriggerService.aidl",
- "core/java/com/android/internal/app/IVoiceActionCheckCallback.aidl",
- "core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl",
- "core/java/com/android/internal/app/IVoiceInteractionSessionListener.aidl",
- "core/java/com/android/internal/app/IVoiceInteractionSessionShowCallback.aidl",
- "core/java/com/android/internal/app/IVoiceInteractor.aidl",
- "core/java/com/android/internal/app/IVoiceInteractorCallback.aidl",
- "core/java/com/android/internal/app/IVoiceInteractorRequest.aidl",
- "core/java/com/android/internal/app/IMediaContainerService.aidl",
- "core/java/com/android/internal/app/procstats/IProcessStats.aidl",
- "core/java/com/android/internal/appwidget/IAppWidgetService.aidl",
- "core/java/com/android/internal/appwidget/IAppWidgetHost.aidl",
- "core/java/com/android/internal/backup/IBackupTransport.aidl",
- "core/java/com/android/internal/backup/IObbBackupService.aidl",
- "core/java/com/android/internal/infra/IAndroidFuture.aidl",
- "core/java/com/android/internal/inputmethod/IInputContentUriToken.aidl",
- "core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl",
- "core/java/com/android/internal/inputmethod/IMultiClientInputMethod.aidl",
- "core/java/com/android/internal/inputmethod/IMultiClientInputMethodPrivilegedOperations.aidl",
- "core/java/com/android/internal/inputmethod/IMultiClientInputMethodSession.aidl",
- "core/java/com/android/internal/net/INetworkWatchlistManager.aidl",
- "core/java/com/android/internal/policy/IKeyguardDrawnCallback.aidl",
- "core/java/com/android/internal/policy/IKeyguardDismissCallback.aidl",
- "core/java/com/android/internal/policy/IKeyguardExitCallback.aidl",
- "core/java/com/android/internal/policy/IKeyguardService.aidl",
- "core/java/com/android/internal/policy/IKeyguardStateCallback.aidl",
- "core/java/com/android/internal/policy/IShortcutService.aidl",
- "core/java/com/android/internal/os/IDropBoxManagerService.aidl",
- "core/java/com/android/internal/os/IParcelFileDescriptorFactory.aidl",
- "core/java/com/android/internal/os/IResultReceiver.aidl",
- "core/java/com/android/internal/os/IShellCallback.aidl",
- "core/java/com/android/internal/statusbar/IStatusBar.aidl",
- "core/java/com/android/internal/statusbar/IStatusBarService.aidl",
- "core/java/com/android/internal/statusbar/RegisterStatusBarResult.aidl",
- "core/java/com/android/internal/textservice/ISpellCheckerService.aidl",
- "core/java/com/android/internal/textservice/ISpellCheckerServiceCallback.aidl",
- "core/java/com/android/internal/textservice/ISpellCheckerSession.aidl",
- "core/java/com/android/internal/textservice/ISpellCheckerSessionListener.aidl",
- "core/java/com/android/internal/textservice/ITextServicesManager.aidl",
- "core/java/com/android/internal/textservice/ITextServicesSessionListener.aidl",
- "core/java/com/android/internal/view/IDragAndDropPermissions.aidl",
- "core/java/com/android/internal/view/IInputContext.aidl",
- "core/java/com/android/internal/view/IInputContextCallback.aidl",
- "core/java/com/android/internal/view/IInputMethod.aidl",
- "core/java/com/android/internal/view/IInputMethodClient.aidl",
- "core/java/com/android/internal/view/IInputMethodManager.aidl",
- "core/java/com/android/internal/view/IInputMethodSession.aidl",
- "core/java/com/android/internal/view/IInputSessionCallback.aidl",
- "core/java/com/android/internal/widget/ICheckCredentialProgressCallback.aidl",
- "core/java/com/android/internal/widget/ILockSettings.aidl",
- "core/java/com/android/internal/widget/IRemoteViewsFactory.aidl",
- "keystore/java/android/security/IKeyChainAliasCallback.aidl",
- "keystore/java/android/security/IKeyChainService.aidl",
- "location/java/android/location/IBatchedLocationCallback.aidl",
- "location/java/android/location/ICountryDetector.aidl",
- "location/java/android/location/ICountryListener.aidl",
- "location/java/android/location/IGeocodeProvider.aidl",
- "location/java/android/location/IGeofenceProvider.aidl",
- "location/java/android/location/IGnssStatusListener.aidl",
- "location/java/android/location/IGnssMeasurementsListener.aidl",
- "location/java/android/location/IGnssNavigationMessageListener.aidl",
- "location/java/android/location/ILocationListener.aidl",
- "location/java/android/location/ILocationManager.aidl",
- "location/java/android/location/IFusedGeofenceHardware.aidl",
- "location/java/android/location/IGpsGeofenceHardware.aidl",
- "location/java/android/location/INetInitiatedListener.aidl",
- "location/java/com/android/internal/location/ILocationProvider.aidl",
- "location/java/com/android/internal/location/ILocationProviderManager.aidl",
- "media/java/android/media/IAudioFocusDispatcher.aidl",
- "media/java/android/media/IAudioRoutesObserver.aidl",
- "media/java/android/media/IAudioService.aidl",
- "media/java/android/media/IAudioServerStateDispatcher.aidl",
- "media/java/android/media/IMediaHTTPConnection.aidl",
- "media/java/android/media/IMediaHTTPService.aidl",
- "media/java/android/media/IMediaResourceMonitor.aidl",
- "media/java/android/media/IMediaRoute2Provider.aidl",
- "media/java/android/media/IMediaRoute2ProviderClient.aidl",
- "media/java/android/media/IMediaRouter2Client.aidl",
- "media/java/android/media/IMediaRouter2Manager.aidl",
- "media/java/android/media/IMediaRouterClient.aidl",
- "media/java/android/media/IMediaRouterService.aidl",
- "media/java/android/media/IMediaScannerListener.aidl",
- "media/java/android/media/IMediaScannerService.aidl",
- "media/java/android/media/IPlaybackConfigDispatcher.aidl",
- ":libaudioclient_aidl",
- "media/java/android/media/IRecordingConfigDispatcher.aidl",
- "media/java/android/media/IRemoteDisplayCallback.aidl",
- "media/java/android/media/IRemoteDisplayProvider.aidl",
- "media/java/android/media/IRemoteVolumeController.aidl",
- "media/java/android/media/IRemoteVolumeObserver.aidl",
- "media/java/android/media/IRingtonePlayer.aidl",
- "media/java/android/media/IVolumeController.aidl",
- "media/java/android/media/audiopolicy/IAudioPolicyCallback.aidl",
- "media/java/android/media/midi/IBluetoothMidiService.aidl",
- "media/java/android/media/midi/IMidiDeviceListener.aidl",
- "media/java/android/media/midi/IMidiDeviceOpenCallback.aidl",
- "media/java/android/media/midi/IMidiDeviceServer.aidl",
- "media/java/android/media/midi/IMidiManager.aidl",
- "media/java/android/media/projection/IMediaProjection.aidl",
- "media/java/android/media/projection/IMediaProjectionCallback.aidl",
- "media/java/android/media/projection/IMediaProjectionManager.aidl",
- "media/java/android/media/projection/IMediaProjectionWatcherCallback.aidl",
- "media/java/android/media/session/IActiveSessionsListener.aidl",
- "media/java/android/media/session/ICallback.aidl",
- "media/java/android/media/session/IOnMediaKeyListener.aidl",
- "media/java/android/media/session/IOnVolumeKeyLongPressListener.aidl",
- "media/java/android/media/session/ISession.aidl",
- "media/java/android/media/session/ISession2TokensListener.aidl",
- "media/java/android/media/session/ISessionCallback.aidl",
- "media/java/android/media/session/ISessionController.aidl",
- "media/java/android/media/session/ISessionControllerCallback.aidl",
- "media/java/android/media/session/ISessionManager.aidl",
- "media/java/android/media/soundtrigger/ISoundTriggerDetectionService.aidl",
- "media/java/android/media/soundtrigger/ISoundTriggerDetectionServiceClient.aidl",
- "media/java/android/media/tv/ITvInputClient.aidl",
- "media/java/android/media/tv/ITvInputHardware.aidl",
- "media/java/android/media/tv/ITvInputHardwareCallback.aidl",
- "media/java/android/media/tv/ITvInputManager.aidl",
- "media/java/android/media/tv/ITvInputManagerCallback.aidl",
- "media/java/android/media/tv/ITvInputService.aidl",
- "media/java/android/media/tv/ITvInputServiceCallback.aidl",
- "media/java/android/media/tv/ITvInputSession.aidl",
- "media/java/android/media/tv/ITvInputSessionCallback.aidl",
- "media/java/android/media/tv/ITvRemoteProvider.aidl",
- "media/java/android/media/tv/ITvRemoteServiceInput.aidl",
- "media/java/android/service/media/IMediaBrowserService.aidl",
- "media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl",
- "telecomm/java/com/android/internal/telecom/ICallRedirectionAdapter.aidl",
- "telecomm/java/com/android/internal/telecom/ICallRedirectionService.aidl",
- "telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl",
- "telecomm/java/com/android/internal/telecom/ICallScreeningService.aidl",
- "telecomm/java/com/android/internal/telecom/IVideoCallback.aidl",
- "telecomm/java/com/android/internal/telecom/IVideoProvider.aidl",
- "telecomm/java/com/android/internal/telecom/IConnectionService.aidl",
- "telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl",
- "telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl",
- "telecomm/java/com/android/internal/telecom/IInCallService.aidl",
- "telecomm/java/com/android/internal/telecom/IPhoneAccountSuggestionCallback.aidl",
- "telecomm/java/com/android/internal/telecom/IPhoneAccountSuggestionService.aidl",
- "telecomm/java/com/android/internal/telecom/ITelecomService.aidl",
- "telecomm/java/com/android/internal/telecom/RemoteServiceCallback.aidl",
- "telephony/java/android/telephony/data/IDataService.aidl",
- "telephony/java/android/telephony/data/IDataServiceCallback.aidl",
- "telephony/java/android/telephony/data/IQualifiedNetworksService.aidl",
- "telephony/java/android/telephony/data/IQualifiedNetworksServiceCallback.aidl",
- "telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl",
- "telephony/java/android/telephony/ims/aidl/IImsCapabilityCallback.aidl",
- "telephony/java/android/telephony/ims/aidl/IImsConfig.aidl",
- "telephony/java/android/telephony/ims/aidl/IImsConfigCallback.aidl",
- "telephony/java/android/telephony/ims/aidl/IImsMmTelFeature.aidl",
- "telephony/java/android/telephony/ims/aidl/IImsMmTelListener.aidl",
- "telephony/java/android/telephony/ims/aidl/IImsRegistration.aidl",
- "telephony/java/android/telephony/ims/aidl/IImsRegistrationCallback.aidl",
- "telephony/java/android/telephony/ims/aidl/IImsRcsFeature.aidl",
- "telephony/java/android/telephony/ims/aidl/IImsServiceController.aidl",
- "telephony/java/android/telephony/ims/aidl/IImsServiceControllerListener.aidl",
- "telephony/java/android/telephony/ims/aidl/IImsSmsListener.aidl",
- "telephony/java/android/telephony/ims/aidl/IRcsMessage.aidl",
- "telephony/java/android/telephony/mbms/IMbmsDownloadSessionCallback.aidl",
- "telephony/java/android/telephony/mbms/IMbmsStreamingSessionCallback.aidl",
- "telephony/java/android/telephony/mbms/IMbmsGroupCallSessionCallback.aidl",
- "telephony/java/android/telephony/mbms/IDownloadStatusListener.aidl",
- "telephony/java/android/telephony/mbms/IDownloadProgressListener.aidl",
- "telephony/java/android/telephony/mbms/IStreamingServiceCallback.aidl",
- "telephony/java/android/telephony/mbms/IGroupCallCallback.aidl",
- "telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl",
- "telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl",
- "telephony/java/android/telephony/mbms/vendor/IMbmsGroupCallService.aidl",
- "telephony/java/android/telephony/ICellInfoCallback.aidl",
- "telephony/java/android/telephony/IFinancialSmsCallback.aidl",
- "telephony/java/android/telephony/INetworkService.aidl",
- "telephony/java/android/telephony/INetworkServiceCallback.aidl",
- "telephony/java/com/android/ims/internal/IImsCallSession.aidl",
- "telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl",
- "telephony/java/com/android/ims/internal/IImsConfig.aidl",
- "telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl",
- "telephony/java/com/android/ims/internal/IImsEcbm.aidl",
- "telephony/java/com/android/ims/internal/IImsEcbmListener.aidl",
- "telephony/java/com/android/ims/internal/IImsExternalCallStateListener.aidl",
- "telephony/java/com/android/ims/internal/IImsFeatureStatusCallback.aidl",
- "telephony/java/com/android/ims/internal/IImsMMTelFeature.aidl",
- "telephony/java/com/android/ims/internal/IImsMultiEndpoint.aidl",
- "telephony/java/com/android/ims/internal/IImsRcsFeature.aidl",
- "telephony/java/com/android/ims/internal/IImsService.aidl",
- "telephony/java/com/android/ims/internal/IImsServiceController.aidl",
- "telephony/java/com/android/ims/internal/IImsServiceFeatureCallback.aidl",
- "telephony/java/com/android/ims/internal/IImsStreamMediaSession.aidl",
- "telephony/java/com/android/ims/internal/IImsUt.aidl",
- "telephony/java/com/android/ims/internal/IImsUtListener.aidl",
- "telephony/java/com/android/ims/internal/IImsVideoCallCallback.aidl",
- "telephony/java/com/android/ims/internal/IImsVideoCallProvider.aidl",
- "telephony/java/com/android/ims/internal/uce/uceservice/IUceService.aidl",
- "telephony/java/com/android/ims/internal/uce/uceservice/IUceListener.aidl",
- "telephony/java/com/android/ims/internal/uce/options/IOptionsService.aidl",
- "telephony/java/com/android/ims/internal/uce/options/IOptionsListener.aidl",
- "telephony/java/com/android/ims/internal/uce/presence/IPresenceService.aidl",
- "telephony/java/com/android/ims/internal/uce/presence/IPresenceListener.aidl",
- "telephony/java/com/android/ims/ImsConfigListener.aidl",
- "telephony/java/com/android/internal/telephony/IApnSourceService.aidl",
- "telephony/java/com/android/internal/telephony/ICarrierConfigLoader.aidl",
- "telephony/java/com/android/internal/telephony/IIntegerConsumer.aidl",
- "telephony/java/com/android/internal/telephony/IMms.aidl",
- "telephony/java/com/android/internal/telephony/INumberVerificationCallback.aidl",
- "telephony/java/com/android/internal/telephony/IOnSubscriptionsChangedListener.aidl",
- "telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl",
- "telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl",
- "telephony/java/com/android/internal/telephony/ISetOpportunisticDataCallback.aidl",
- "telephony/java/com/android/internal/telephony/ISms.aidl",
- "telephony/java/com/android/internal/telephony/ISub.aidl",
- "telephony/java/com/android/internal/telephony/IOns.aidl",
- "telephony/java/com/android/internal/telephony/ITelephony.aidl",
- "telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl",
- "telephony/java/com/android/internal/telephony/IUpdateAvailableNetworksCallback.aidl",
- "telephony/java/com/android/internal/telephony/IWapPushManager.aidl",
- "telephony/java/com/android/internal/telephony/euicc/IAuthenticateServerCallback.aidl",
- "telephony/java/com/android/internal/telephony/euicc/ICancelSessionCallback.aidl",
- "telephony/java/com/android/internal/telephony/euicc/IDeleteProfileCallback.aidl",
- "telephony/java/com/android/internal/telephony/euicc/IDisableProfileCallback.aidl",
- "telephony/java/com/android/internal/telephony/euicc/IEuiccCardController.aidl",
- "telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl",
- "telephony/java/com/android/internal/telephony/euicc/IGetAllProfilesCallback.aidl",
- "telephony/java/com/android/internal/telephony/euicc/IGetDefaultSmdpAddressCallback.aidl",
- "telephony/java/com/android/internal/telephony/euicc/IGetEuiccChallengeCallback.aidl",
- "telephony/java/com/android/internal/telephony/euicc/IGetEuiccInfo1Callback.aidl",
- "telephony/java/com/android/internal/telephony/euicc/IGetEuiccInfo2Callback.aidl",
- "telephony/java/com/android/internal/telephony/euicc/IGetProfileCallback.aidl",
- "telephony/java/com/android/internal/telephony/euicc/IGetRulesAuthTableCallback.aidl",
- "telephony/java/com/android/internal/telephony/euicc/IGetSmdsAddressCallback.aidl",
- "telephony/java/com/android/internal/telephony/euicc/IListNotificationsCallback.aidl",
- "telephony/java/com/android/internal/telephony/euicc/ILoadBoundProfilePackageCallback.aidl",
- "telephony/java/com/android/internal/telephony/euicc/IPrepareDownloadCallback.aidl",
- "telephony/java/com/android/internal/telephony/euicc/IRemoveNotificationFromListCallback.aidl",
- "telephony/java/com/android/internal/telephony/euicc/IResetMemoryCallback.aidl",
- "telephony/java/com/android/internal/telephony/euicc/IRetrieveNotificationCallback.aidl",
- "telephony/java/com/android/internal/telephony/euicc/IRetrieveNotificationListCallback.aidl",
- "telephony/java/com/android/internal/telephony/euicc/ISetDefaultSmdpAddressCallback.aidl",
- "telephony/java/com/android/internal/telephony/euicc/ISetNicknameCallback.aidl",
- "telephony/java/com/android/internal/telephony/euicc/ISwitchToProfileCallback.aidl",
- "wifi/java/android/net/wifi/INetworkRequestMatchCallback.aidl",
- "wifi/java/android/net/wifi/INetworkRequestUserSelectionCallback.aidl",
- "wifi/java/android/net/wifi/ISoftApCallback.aidl",
- "wifi/java/android/net/wifi/ITrafficStateCallback.aidl",
- "wifi/java/android/net/wifi/IWifiManager.aidl",
- "wifi/java/android/net/wifi/IOnWifiUsabilityStatsListener.aidl",
- "wifi/java/android/net/wifi/aware/IWifiAwareDiscoverySessionCallback.aidl",
- "wifi/java/android/net/wifi/aware/IWifiAwareEventCallback.aidl",
- "wifi/java/android/net/wifi/aware/IWifiAwareMacAddressProvider.aidl",
- "wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl",
- "wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl",
- "wifi/java/android/net/wifi/rtt/IRttCallback.aidl",
- "wifi/java/android/net/wifi/rtt/IWifiRttManager.aidl",
- "wifi/java/android/net/wifi/hotspot2/IProvisioningCallback.aidl",
- "wifi/java/android/net/wifi/IDppCallback.aidl",
- "wifi/java/android/net/wifi/IWifiScanner.aidl",
- "packages/services/PacProcessor/com/android/net/IProxyService.aidl",
- "packages/services/Proxy/com/android/net/IProxyCallback.aidl",
- "packages/services/Proxy/com/android/net/IProxyPortListener.aidl",
- "core/java/android/service/quicksettings/IQSService.aidl",
- "core/java/android/service/quicksettings/IQSTileService.aidl",
-
- ":libupdate_engine_aidl",
-
- ":storaged_aidl",
- ":vold_aidl",
- ":gsiservice_aidl",
- ":installd_aidl",
- ":dumpstate_aidl",
- ":incidentcompanion_aidl",
-
- "lowpan/java/android/net/lowpan/ILowpanEnergyScanCallback.aidl",
- "lowpan/java/android/net/lowpan/ILowpanNetScanCallback.aidl",
- "lowpan/java/android/net/lowpan/ILowpanInterfaceListener.aidl",
- "lowpan/java/android/net/lowpan/ILowpanInterface.aidl",
- "lowpan/java/android/net/lowpan/ILowpanManagerListener.aidl",
- "lowpan/java/android/net/lowpan/ILowpanManager.aidl",
-
- "core/java/android/app/admin/SecurityLogTags.logtags",
- "core/java/android/content/EventLogTags.logtags",
- "core/java/android/speech/tts/EventLogTags.logtags",
- "core/java/android/net/EventLogTags.logtags",
- "core/java/android/os/EventLogTags.logtags",
- "core/java/android/webkit/EventLogTags.logtags",
- "core/java/com/android/internal/app/EventLogTags.logtags",
- "core/java/com/android/internal/logging/EventLogTags.logtags",
- "core/java/com/android/server/DropboxLogTags.logtags",
- "core/java/org/chromium/arc/EventLogTags.logtags",
-
- ":framework-statslog-gen",
- ],
+ ":framework-defaults-java-srcs",
+ ] + framework_srcs,
aidl: {
- include_dirs: [
- "system/update_engine/binder_bindings",
- "frameworks/native/aidl/binder",
- "frameworks/native/cmds/dumpstate/binder",
- "frameworks/native/libs/incidentcompanion/binder",
- "frameworks/av/camera/aidl",
- "frameworks/av/media/libaudioclient/aidl",
- "frameworks/native/aidl/gui",
- "frameworks/native/libs/incidentcompanion/binder",
- "system/core/gatekeeperd/binder",
- "system/core/storaged/binder",
- "system/vold/binder",
- "system/gsid/aidl",
- "system/bt/binder",
- "system/security/keystore/binder",
- ],
-
+ local_include_dirs: framework_aidl_local_include_dirs,
+ include_dirs: framework_aidl_external_include_dirs,
generate_get_transaction_name: true,
},
@@ -845,10 +248,6 @@
name: "framework-minus-apex",
defaults: ["framework-defaults"],
javac_shard_size: 150,
- required: [
- "framework-platform-compat-config",
- "libcore-platform-compat-config",
- ],
}
java_library {
@@ -859,6 +258,10 @@
"framework-minus-apex",
"jobscheduler-framework",
],
+ required: [
+ "framework-platform-compat-config",
+ "libcore-platform-compat-config",
+ ],
sdk_version: "core_platform",
}
@@ -1769,10 +1172,10 @@
name: "hiddenapi-mappings",
defaults: ["metalava-api-stubs-default"],
srcs: [
- ":openjdk_java_files",
+ ":framework-defaults-java-srcs",
":non_openjdk_java_files",
+ ":openjdk_java_files",
":opt-telephony-common-srcs",
- "core/java/**/*.java",
],
arg_files: [
"core/res/AndroidManifest.xml",
@@ -1827,6 +1230,7 @@
last_released: {
api_file: ":last-released-public-api",
removed_api_file: "api/removed.txt",
+ baseline_file: ":public-api-incompatibilities-with-last-released",
},
},
jdiff_enabled: true,
@@ -1852,6 +1256,7 @@
last_released: {
api_file: ":last-released-system-api",
removed_api_file: "api/system-removed.txt",
+ baseline_file: ":system-api-incompatibilities-with-last-released"
},
},
jdiff_enabled: true,
@@ -1906,7 +1311,9 @@
// annotations to private apis
aidl_mapping {
name: "framework-aidl-mappings",
- srcs: [":framework-defaults"],
+ srcs: framework_srcs,
+ local_include_dirs: framework_aidl_local_include_dirs,
+ include_dirs: framework_aidl_external_include_dirs,
output: "framework-aidl-mappings.txt",
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/GrantedUriPermissions.java b/apex/jobscheduler/service/java/com/android/server/job/GrantedUriPermissions.java
index 005b189..b7e8cf6 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/GrantedUriPermissions.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/GrantedUriPermissions.java
@@ -16,7 +16,6 @@
package com.android.server.job;
-import android.app.IActivityManager;
import android.app.UriGrantsManager;
import android.content.ClipData;
import android.content.ContentProvider;
@@ -40,7 +39,7 @@
private final IBinder mPermissionOwner;
private final ArrayList<Uri> mUris = new ArrayList<>();
- private GrantedUriPermissions(IActivityManager am, int grantFlags, int uid, String tag)
+ private GrantedUriPermissions(int grantFlags, int uid, String tag)
throws RemoteException {
mGrantFlags = grantFlags;
mSourceUserId = UserHandle.getUserId(uid);
@@ -49,7 +48,7 @@
.getService(UriGrantsManagerInternal.class).newUriPermissionOwner("job: " + tag);
}
- public void revoke(IActivityManager am) {
+ public void revoke() {
for (int i = mUris.size()-1; i >= 0; i--) {
LocalServices.getService(UriGrantsManagerInternal.class).revokeUriPermissionFromOwner(
mPermissionOwner, mUris.get(i), mGrantFlags, mSourceUserId);
@@ -62,7 +61,7 @@
|Intent.FLAG_GRANT_READ_URI_PERMISSION)) != 0;
}
- public static GrantedUriPermissions createFromIntent(IActivityManager am, Intent intent,
+ public static GrantedUriPermissions createFromIntent(Intent intent,
int sourceUid, String targetPackage, int targetUserId, String tag) {
int grantFlags = intent.getFlags();
if (!checkGrantFlags(grantFlags)) {
@@ -73,44 +72,44 @@
Uri data = intent.getData();
if (data != null) {
- perms = grantUri(am, data, sourceUid, targetPackage, targetUserId, grantFlags, tag,
+ perms = grantUri(data, sourceUid, targetPackage, targetUserId, grantFlags, tag,
perms);
}
ClipData clip = intent.getClipData();
if (clip != null) {
- perms = grantClip(am, clip, sourceUid, targetPackage, targetUserId, grantFlags, tag,
+ perms = grantClip(clip, sourceUid, targetPackage, targetUserId, grantFlags, tag,
perms);
}
return perms;
}
- public static GrantedUriPermissions createFromClip(IActivityManager am, ClipData clip,
+ public static GrantedUriPermissions createFromClip(ClipData clip,
int sourceUid, String targetPackage, int targetUserId, int grantFlags, String tag) {
if (!checkGrantFlags(grantFlags)) {
return null;
}
GrantedUriPermissions perms = null;
if (clip != null) {
- perms = grantClip(am, clip, sourceUid, targetPackage, targetUserId, grantFlags,
+ perms = grantClip(clip, sourceUid, targetPackage, targetUserId, grantFlags,
tag, perms);
}
return perms;
}
- private static GrantedUriPermissions grantClip(IActivityManager am, ClipData clip,
+ private static GrantedUriPermissions grantClip(ClipData clip,
int sourceUid, String targetPackage, int targetUserId, int grantFlags, String tag,
GrantedUriPermissions curPerms) {
final int N = clip.getItemCount();
for (int i = 0; i < N; i++) {
- curPerms = grantItem(am, clip.getItemAt(i), sourceUid, targetPackage, targetUserId,
+ curPerms = grantItem(clip.getItemAt(i), sourceUid, targetPackage, targetUserId,
grantFlags, tag, curPerms);
}
return curPerms;
}
- private static GrantedUriPermissions grantUri(IActivityManager am, Uri uri,
+ private static GrantedUriPermissions grantUri(Uri uri,
int sourceUid, String targetPackage, int targetUserId, int grantFlags, String tag,
GrantedUriPermissions curPerms) {
try {
@@ -118,7 +117,7 @@
UserHandle.getUserId(sourceUid));
uri = ContentProvider.getUriWithoutUserId(uri);
if (curPerms == null) {
- curPerms = new GrantedUriPermissions(am, grantFlags, sourceUid, tag);
+ curPerms = new GrantedUriPermissions(grantFlags, sourceUid, tag);
}
UriGrantsManager.getService().grantUriPermissionFromOwner(curPerms.mPermissionOwner,
sourceUid, targetPackage, uri, grantFlags, sourceUserId, targetUserId);
@@ -129,16 +128,16 @@
return curPerms;
}
- private static GrantedUriPermissions grantItem(IActivityManager am, ClipData.Item item,
+ private static GrantedUriPermissions grantItem(ClipData.Item item,
int sourceUid, String targetPackage, int targetUserId, int grantFlags, String tag,
GrantedUriPermissions curPerms) {
if (item.getUri() != null) {
- curPerms = grantUri(am, item.getUri(), sourceUid, targetPackage, targetUserId,
+ curPerms = grantUri(item.getUri(), sourceUid, targetPackage, targetUserId,
grantFlags, tag, curPerms);
}
Intent intent = item.getIntent();
if (intent != null && intent.getData() != null) {
- curPerms = grantUri(am, intent.getData(), sourceUid, targetPackage, targetUserId,
+ curPerms = grantUri(intent.getData(), sourceUid, targetPackage, targetUserId,
grantFlags, tag, curPerms);
}
return curPerms;
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 5ba563c..a633350 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -89,7 +89,7 @@
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.server.AppStateTracker;
-import com.android.server.DeviceIdleController;
+import com.android.server.DeviceIdleInternal;
import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.job.JobSchedulerServiceDumpProto.ActiveJob;
@@ -207,7 +207,7 @@
PackageManagerInternal mLocalPM;
ActivityManagerInternal mActivityManagerInternal;
IBatteryStats mBatteryStats;
- DeviceIdleController.LocalService mLocalDeviceIdleController;
+ DeviceIdleInternal mLocalDeviceIdleController;
AppStateTracker mAppStateTracker;
final UsageStatsManagerInternal mUsageStats;
@@ -963,7 +963,7 @@
// changing. We can just directly enqueue this work in to the job.
if (toCancel.getJob().equals(job)) {
- toCancel.enqueueWorkLocked(ActivityManager.getService(), work);
+ toCancel.enqueueWorkLocked(work);
// If any of work item is enqueued when the source is in the foreground,
// exempt the entire job.
@@ -992,11 +992,11 @@
}
// This may throw a SecurityException.
- jobStatus.prepareLocked(ActivityManager.getService());
+ jobStatus.prepareLocked();
if (work != null) {
// If work has been supplied, enqueue it into the new job.
- jobStatus.enqueueWorkLocked(ActivityManager.getService(), work);
+ jobStatus.enqueueWorkLocked(work);
}
if (toCancel != null) {
@@ -1144,7 +1144,7 @@
*/
private void cancelJobImplLocked(JobStatus cancelled, JobStatus incomingJob, String reason) {
if (DEBUG) Slog.d(TAG, "CANCEL: " + cancelled.toShortString());
- cancelled.unprepareLocked(ActivityManager.getService());
+ cancelled.unprepareLocked();
stopTrackingJobLocked(cancelled, incomingJob, true /* writeBack */);
// Remove from pending queue.
if (mPendingJobs.remove(cancelled)) {
@@ -1399,8 +1399,8 @@
mReadyToRock = true;
mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
BatteryStats.SERVICE_NAME));
- mLocalDeviceIdleController
- = LocalServices.getService(DeviceIdleController.LocalService.class);
+ mLocalDeviceIdleController =
+ LocalServices.getService(DeviceIdleInternal.class);
// Create the "runners".
for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) {
mActiveServices.add(
@@ -1449,7 +1449,7 @@
private boolean stopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob,
boolean removeFromPersisted) {
// Deal with any remaining work items in the old job.
- jobStatus.stopTrackingJobLocked(ActivityManager.getService(), incomingJob);
+ jobStatus.stopTrackingJobLocked(incomingJob);
// Remove from store as well as controllers.
final boolean removed = mJobs.remove(jobStatus, removeFromPersisted);
@@ -1705,7 +1705,7 @@
if (rescheduledJob != null) {
try {
- rescheduledJob.prepareLocked(ActivityManager.getService());
+ rescheduledJob.prepareLocked();
} catch (SecurityException e) {
Slog.w(TAG, "Unable to regrant job permissions for " + rescheduledJob);
}
@@ -1713,13 +1713,13 @@
} else if (jobStatus.getJob().isPeriodic()) {
JobStatus rescheduledPeriodic = getRescheduleJobForPeriodic(jobStatus);
try {
- rescheduledPeriodic.prepareLocked(ActivityManager.getService());
+ rescheduledPeriodic.prepareLocked();
} catch (SecurityException e) {
Slog.w(TAG, "Unable to regrant job permissions for " + rescheduledPeriodic);
}
startTrackingJobLocked(rescheduledPeriodic, jobStatus);
}
- jobStatus.unprepareLocked(ActivityManager.getService());
+ jobStatus.unprepareLocked();
reportActiveLocked();
mHandler.obtainMessage(MSG_CHECK_JOB_GREEDY).sendToTarget();
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
index 4d9f133..782e646 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
@@ -18,7 +18,6 @@
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
-import android.app.ActivityManager;
import android.app.job.IJobCallback;
import android.app.job.IJobService;
import android.app.job.JobInfo;
@@ -389,7 +388,7 @@
try {
synchronized (mLock) {
assertCallerLocked(cb);
- return mRunningJob.completeWorkLocked(ActivityManager.getService(), workId);
+ return mRunningJob.completeWorkLocked(workId);
}
} finally {
Binder.restoreCallingIdentity(ident);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
index 4321fc7..c2bdb6c 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
@@ -20,8 +20,6 @@
import static com.android.server.job.JobSchedulerService.sSystemClock;
import android.annotation.Nullable;
-import android.app.ActivityManager;
-import android.app.IActivityManager;
import android.app.job.JobInfo;
import android.content.ComponentName;
import android.content.Context;
@@ -180,7 +178,6 @@
public void getRtcCorrectedJobsLocked(final ArrayList<JobStatus> toAdd,
final ArrayList<JobStatus> toRemove) {
final long elapsedNow = sElapsedRealtimeClock.millis();
- final IActivityManager am = ActivityManager.getService();
// Find the jobs that need to be fixed up, collecting them for post-iteration
// replacement with their new versions
@@ -192,7 +189,7 @@
JobStatus newJob = new JobStatus(job,
elapsedRuntimes.first, elapsedRuntimes.second,
0, job.getLastSuccessfulRunTime(), job.getLastFailedRunTime());
- newJob.prepareLocked(am);
+ newJob.prepareLocked();
toAdd.add(newJob);
toRemove.add(job);
}
@@ -667,10 +664,9 @@
jobs = readJobMapImpl(fis, rtcGood);
if (jobs != null) {
long now = sElapsedRealtimeClock.millis();
- IActivityManager am = ActivityManager.getService();
for (int i=0; i<jobs.size(); i++) {
JobStatus js = jobs.get(i);
- js.prepareLocked(am);
+ js.prepareLocked();
js.enqueueTime = now;
this.jobSet.add(js);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java
index 0b67971..01f5fa6 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java
@@ -34,7 +34,7 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.IndentingPrintWriter;
-import com.android.server.DeviceIdleController;
+import com.android.server.DeviceIdleInternal;
import com.android.server.LocalServices;
import com.android.server.job.JobSchedulerService;
import com.android.server.job.StateControllerProto;
@@ -66,7 +66,7 @@
private final DeviceIdleUpdateFunctor mDeviceIdleUpdateFunctor;
private final DeviceIdleJobsDelayHandler mHandler;
private final PowerManager mPowerManager;
- private final DeviceIdleController.LocalService mLocalDeviceIdleController;
+ private final DeviceIdleInternal mLocalDeviceIdleController;
/**
* True when in device idle mode, so we don't want to schedule any jobs.
@@ -123,7 +123,7 @@
// Register for device idle mode changes
mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mLocalDeviceIdleController =
- LocalServices.getService(DeviceIdleController.LocalService.class);
+ LocalServices.getService(DeviceIdleInternal.class);
mDeviceIdleWhitelistAppIds = mLocalDeviceIdleController.getPowerSaveWhitelistUserAppIds();
mPowerSaveTempWhitelistAppIds =
mLocalDeviceIdleController.getPowerSaveTempWhitelistAppIds();
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index 1133f7b..adb4314 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -20,7 +20,6 @@
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
import android.app.AppGlobals;
-import android.app.IActivityManager;
import android.app.job.JobInfo;
import android.app.job.JobWorkItem;
import android.content.ClipData;
@@ -528,7 +527,7 @@
/*innerFlags=*/ 0);
}
- public void enqueueWorkLocked(IActivityManager am, JobWorkItem work) {
+ public void enqueueWorkLocked(JobWorkItem work) {
if (pendingWork == null) {
pendingWork = new ArrayList<>();
}
@@ -536,7 +535,7 @@
nextPendingWorkId++;
if (work.getIntent() != null
&& GrantedUriPermissions.checkGrantFlags(work.getIntent().getFlags())) {
- work.setGrants(GrantedUriPermissions.createFromIntent(am, work.getIntent(), sourceUid,
+ work.setGrants(GrantedUriPermissions.createFromIntent(work.getIntent(), sourceUid,
sourcePackageName, sourceUserId, toShortString()));
}
pendingWork.add(work);
@@ -567,20 +566,20 @@
return executingWork != null && executingWork.size() > 0;
}
- private static void ungrantWorkItem(IActivityManager am, JobWorkItem work) {
+ private static void ungrantWorkItem(JobWorkItem work) {
if (work.getGrants() != null) {
- ((GrantedUriPermissions)work.getGrants()).revoke(am);
+ ((GrantedUriPermissions)work.getGrants()).revoke();
}
}
- public boolean completeWorkLocked(IActivityManager am, int workId) {
+ public boolean completeWorkLocked(int workId) {
if (executingWork != null) {
final int N = executingWork.size();
for (int i = 0; i < N; i++) {
JobWorkItem work = executingWork.get(i);
if (work.getWorkId() == workId) {
executingWork.remove(i);
- ungrantWorkItem(am, work);
+ ungrantWorkItem(work);
return true;
}
}
@@ -588,16 +587,16 @@
return false;
}
- private static void ungrantWorkList(IActivityManager am, ArrayList<JobWorkItem> list) {
+ private static void ungrantWorkList(ArrayList<JobWorkItem> list) {
if (list != null) {
final int N = list.size();
for (int i = 0; i < N; i++) {
- ungrantWorkItem(am, list.get(i));
+ ungrantWorkItem(list.get(i));
}
}
}
- public void stopTrackingJobLocked(IActivityManager am, JobStatus incomingJob) {
+ public void stopTrackingJobLocked(JobStatus incomingJob) {
if (incomingJob != null) {
// We are replacing with a new job -- transfer the work! We do any executing
// work first, since that was originally at the front of the pending work.
@@ -615,15 +614,15 @@
incomingJob.updateEstimatedNetworkBytesLocked();
} else {
// We are completely stopping the job... need to clean up work.
- ungrantWorkList(am, pendingWork);
+ ungrantWorkList(pendingWork);
pendingWork = null;
- ungrantWorkList(am, executingWork);
+ ungrantWorkList(executingWork);
executingWork = null;
}
updateEstimatedNetworkBytesLocked();
}
- public void prepareLocked(IActivityManager am) {
+ public void prepareLocked() {
if (prepared) {
Slog.wtf(TAG, "Already prepared: " + this);
return;
@@ -634,12 +633,12 @@
}
final ClipData clip = job.getClipData();
if (clip != null) {
- uriPerms = GrantedUriPermissions.createFromClip(am, clip, sourceUid, sourcePackageName,
+ uriPerms = GrantedUriPermissions.createFromClip(clip, sourceUid, sourcePackageName,
sourceUserId, job.getClipGrantFlags(), toShortString());
}
}
- public void unprepareLocked(IActivityManager am) {
+ public void unprepareLocked() {
if (!prepared) {
Slog.wtf(TAG, "Hasn't been prepared: " + this);
if (DEBUG_PREPARE && unpreparedPoint != null) {
@@ -652,7 +651,7 @@
unpreparedPoint = new Throwable().fillInStackTrace();
}
if (uriPerms != null) {
- uriPerms.revoke(am);
+ uriPerms.revoke();
uriPerms = null;
}
}
diff --git a/api/current.txt b/api/current.txt
index 9473a84..593710314 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6727,6 +6727,7 @@
method @Nullable public java.util.List<android.os.PersistableBundle> getTrustAgentConfiguration(@Nullable android.content.ComponentName, @NonNull android.content.ComponentName);
method @NonNull public android.os.Bundle getUserRestrictions(@NonNull android.content.ComponentName);
method @Nullable public String getWifiMacAddress(@NonNull android.content.ComponentName);
+ method public boolean grantKeyPairToApp(@Nullable android.content.ComponentName, @NonNull String, @NonNull String);
method public boolean hasCaCertInstalled(@Nullable android.content.ComponentName, byte[]);
method public boolean hasGrantedPolicy(@NonNull android.content.ComponentName, int);
method public boolean installCaCert(@Nullable android.content.ComponentName, byte[]);
@@ -6773,6 +6774,7 @@
method @Nullable public java.util.List<android.app.admin.NetworkEvent> retrieveNetworkLogs(@Nullable android.content.ComponentName, long);
method @Nullable public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrievePreRebootSecurityLogs(@NonNull android.content.ComponentName);
method @Nullable public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrieveSecurityLogs(@NonNull android.content.ComponentName);
+ method public boolean revokeKeyPairFromApp(@Nullable android.content.ComponentName, @NonNull String, @NonNull String);
method public void setAccountManagementDisabled(@NonNull android.content.ComponentName, String, boolean);
method public void setAffiliationIds(@NonNull android.content.ComponentName, @NonNull java.util.Set<java.lang.String>);
method public void setAlwaysOnVpnPackage(@NonNull android.content.ComponentName, @Nullable String, boolean) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -6796,7 +6798,6 @@
method @WorkerThread public int setGlobalPrivateDnsModeSpecifiedHost(@NonNull android.content.ComponentName, @NonNull String);
method public void setGlobalSetting(@NonNull android.content.ComponentName, String, String);
method public void setKeepUninstalledPackages(@Nullable android.content.ComponentName, @NonNull java.util.List<java.lang.String>);
- method public boolean setKeyGrantForApp(@Nullable android.content.ComponentName, @NonNull String, @NonNull String, boolean);
method public boolean setKeyPairCertificate(@Nullable android.content.ComponentName, @NonNull String, @NonNull java.util.List<java.security.cert.Certificate>, boolean);
method public boolean setKeyguardDisabled(@NonNull android.content.ComponentName, boolean);
method public void setKeyguardDisabledFeatures(@NonNull android.content.ComponentName, int);
@@ -18417,8 +18418,12 @@
field public static final int EARLY_DYNASTIC_CUNEIFORM_ID = 257; // 0x101
field public static final android.icu.lang.UCharacter.UnicodeBlock EGYPTIAN_HIEROGLYPHS;
field public static final int EGYPTIAN_HIEROGLYPHS_ID = 194; // 0xc2
+ field public static final android.icu.lang.UCharacter.UnicodeBlock EGYPTIAN_HIEROGLYPH_FORMAT_CONTROLS;
+ field public static final int EGYPTIAN_HIEROGLYPH_FORMAT_CONTROLS_ID = 292; // 0x124
field public static final android.icu.lang.UCharacter.UnicodeBlock ELBASAN;
field public static final int ELBASAN_ID = 226; // 0xe2
+ field public static final android.icu.lang.UCharacter.UnicodeBlock ELYMAIC;
+ field public static final int ELYMAIC_ID = 293; // 0x125
field public static final android.icu.lang.UCharacter.UnicodeBlock EMOTICONS;
field public static final int EMOTICONS_ID = 206; // 0xce
field public static final android.icu.lang.UCharacter.UnicodeBlock ENCLOSED_ALPHANUMERICS;
@@ -18645,6 +18650,8 @@
field public static final int MYANMAR_ID = 28; // 0x1c
field public static final android.icu.lang.UCharacter.UnicodeBlock NABATAEAN;
field public static final int NABATAEAN_ID = 239; // 0xef
+ field public static final android.icu.lang.UCharacter.UnicodeBlock NANDINAGARI;
+ field public static final int NANDINAGARI_ID = 294; // 0x126
field public static final android.icu.lang.UCharacter.UnicodeBlock NEWA;
field public static final int NEWA_ID = 270; // 0x10e
field public static final android.icu.lang.UCharacter.UnicodeBlock NEW_TAI_LUE;
@@ -18656,6 +18663,8 @@
field public static final int NUMBER_FORMS_ID = 45; // 0x2d
field public static final android.icu.lang.UCharacter.UnicodeBlock NUSHU;
field public static final int NUSHU_ID = 277; // 0x115
+ field public static final android.icu.lang.UCharacter.UnicodeBlock NYIAKENG_PUACHUE_HMONG;
+ field public static final int NYIAKENG_PUACHUE_HMONG_ID = 295; // 0x127
field public static final android.icu.lang.UCharacter.UnicodeBlock OGHAM;
field public static final int OGHAM_ID = 34; // 0x22
field public static final android.icu.lang.UCharacter.UnicodeBlock OLD_HUNGARIAN;
@@ -18686,6 +18695,8 @@
field public static final int OSAGE_ID = 271; // 0x10f
field public static final android.icu.lang.UCharacter.UnicodeBlock OSMANYA;
field public static final int OSMANYA_ID = 122; // 0x7a
+ field public static final android.icu.lang.UCharacter.UnicodeBlock OTTOMAN_SIYAQ_NUMBERS;
+ field public static final int OTTOMAN_SIYAQ_NUMBERS_ID = 296; // 0x128
field public static final android.icu.lang.UCharacter.UnicodeBlock PAHAWH_HMONG;
field public static final int PAHAWH_HMONG_ID = 243; // 0xf3
field public static final android.icu.lang.UCharacter.UnicodeBlock PALMYRENE;
@@ -18734,6 +18745,8 @@
field public static final int SINHALA_ID = 24; // 0x18
field public static final android.icu.lang.UCharacter.UnicodeBlock SMALL_FORM_VARIANTS;
field public static final int SMALL_FORM_VARIANTS_ID = 84; // 0x54
+ field public static final android.icu.lang.UCharacter.UnicodeBlock SMALL_KANA_EXTENSION;
+ field public static final int SMALL_KANA_EXTENSION_ID = 297; // 0x129
field public static final android.icu.lang.UCharacter.UnicodeBlock SOGDIAN;
field public static final int SOGDIAN_ID = 291; // 0x123
field public static final android.icu.lang.UCharacter.UnicodeBlock SORA_SOMPENG;
@@ -18770,6 +18783,8 @@
field public static final int SUTTON_SIGNWRITING_ID = 262; // 0x106
field public static final android.icu.lang.UCharacter.UnicodeBlock SYLOTI_NAGRI;
field public static final int SYLOTI_NAGRI_ID = 143; // 0x8f
+ field public static final android.icu.lang.UCharacter.UnicodeBlock SYMBOLS_AND_PICTOGRAPHS_EXTENDED_A;
+ field public static final int SYMBOLS_AND_PICTOGRAPHS_EXTENDED_A_ID = 298; // 0x12a
field public static final android.icu.lang.UCharacter.UnicodeBlock SYRIAC;
field public static final int SYRIAC_ID = 13; // 0xd
field public static final android.icu.lang.UCharacter.UnicodeBlock SYRIAC_SUPPLEMENT;
@@ -18792,6 +18807,8 @@
field public static final int TAKRI_ID = 220; // 0xdc
field public static final android.icu.lang.UCharacter.UnicodeBlock TAMIL;
field public static final int TAMIL_ID = 20; // 0x14
+ field public static final android.icu.lang.UCharacter.UnicodeBlock TAMIL_SUPPLEMENT;
+ field public static final int TAMIL_SUPPLEMENT_ID = 299; // 0x12b
field public static final android.icu.lang.UCharacter.UnicodeBlock TANGUT;
field public static final android.icu.lang.UCharacter.UnicodeBlock TANGUT_COMPONENTS;
field public static final int TANGUT_COMPONENTS_ID = 273; // 0x111
@@ -18826,6 +18843,8 @@
field public static final int VEDIC_EXTENSIONS_ID = 175; // 0xaf
field public static final android.icu.lang.UCharacter.UnicodeBlock VERTICAL_FORMS;
field public static final int VERTICAL_FORMS_ID = 145; // 0x91
+ field public static final android.icu.lang.UCharacter.UnicodeBlock WANCHO;
+ field public static final int WANCHO_ID = 300; // 0x12c
field public static final android.icu.lang.UCharacter.UnicodeBlock WARANG_CITI;
field public static final int WARANG_CITI_ID = 252; // 0xfc
field public static final android.icu.lang.UCharacter.UnicodeBlock YIJING_HEXAGRAM_SYMBOLS;
@@ -19138,6 +19157,7 @@
field public static final int EASTERN_SYRIAC = 97; // 0x61
field public static final int EGYPTIAN_HIEROGLYPHS = 71; // 0x47
field public static final int ELBASAN = 136; // 0x88
+ field public static final int ELYMAIC = 185; // 0xb9
field public static final int ESTRANGELO_SYRIAC = 95; // 0x5f
field public static final int ETHIOPIC = 11; // 0xb
field public static final int GEORGIAN = 12; // 0xc
@@ -19217,10 +19237,12 @@
field public static final int MYANMAR = 28; // 0x1c
field public static final int NABATAEAN = 143; // 0x8f
field public static final int NAKHI_GEBA = 132; // 0x84
+ field public static final int NANDINAGARI = 187; // 0xbb
field public static final int NEWA = 170; // 0xaa
field public static final int NEW_TAI_LUE = 59; // 0x3b
field public static final int NKO = 87; // 0x57
field public static final int NUSHU = 150; // 0x96
+ field public static final int NYIAKENG_PUACHUE_HMONG = 186; // 0xba
field public static final int OGHAM = 29; // 0x1d
field public static final int OLD_CHURCH_SLAVONIC_CYRILLIC = 68; // 0x44
field public static final int OLD_HUNGARIAN = 76; // 0x4c
@@ -19284,6 +19306,7 @@
field public static final int UNWRITTEN_LANGUAGES = 102; // 0x66
field public static final int VAI = 99; // 0x63
field public static final int VISIBLE_SPEECH = 100; // 0x64
+ field public static final int WANCHO = 188; // 0xbc
field public static final int WARANG_CITI = 146; // 0x92
field public static final int WESTERN_SYRIAC = 96; // 0x60
field public static final int WOLEAI = 155; // 0x9b
@@ -20072,6 +20095,7 @@
method public String getDateTimeFormat();
method public String getDecimal();
method public static android.icu.text.DateTimePatternGenerator getEmptyInstance();
+ method public String getFieldDisplayName(int, android.icu.text.DateTimePatternGenerator.DisplayWidth);
method public static android.icu.text.DateTimePatternGenerator getInstance();
method public static android.icu.text.DateTimePatternGenerator getInstance(android.icu.util.ULocale);
method public static android.icu.text.DateTimePatternGenerator getInstance(java.util.Locale);
@@ -20105,6 +20129,12 @@
field public static final int ZONE = 15; // 0xf
}
+ public enum DateTimePatternGenerator.DisplayWidth {
+ enum_constant public static final android.icu.text.DateTimePatternGenerator.DisplayWidth ABBREVIATED;
+ enum_constant public static final android.icu.text.DateTimePatternGenerator.DisplayWidth NARROW;
+ enum_constant public static final android.icu.text.DateTimePatternGenerator.DisplayWidth WIDE;
+ }
+
public static final class DateTimePatternGenerator.PatternInfo {
ctor public DateTimePatternGenerator.PatternInfo();
field public static final int BASE_CONFLICT = 1; // 0x1
@@ -21659,6 +21689,7 @@
method public static boolean isAvailable(String, java.util.Date, java.util.Date);
method public java.util.Currency toJavaCurrency();
field public static final int LONG_NAME = 1; // 0x1
+ field public static final int NARROW_SYMBOL_NAME = 3; // 0x3
field public static final int PLURAL_LONG_NAME = 2; // 0x2
field public static final int SYMBOL_NAME = 0; // 0x0
}
@@ -21861,6 +21892,7 @@
ctor public JapaneseCalendar(int, int, int, int, int, int);
field public static final int HEISEI;
field public static final int MEIJI;
+ field public static final int REIWA;
field public static final int SHOWA;
field public static final int TAISHO;
}
@@ -22336,6 +22368,8 @@
field public static final android.icu.util.VersionInfo UCOL_RUNTIME_VERSION;
field public static final android.icu.util.VersionInfo UNICODE_10_0;
field public static final android.icu.util.VersionInfo UNICODE_11_0;
+ field public static final android.icu.util.VersionInfo UNICODE_12_0;
+ field public static final android.icu.util.VersionInfo UNICODE_12_1;
field public static final android.icu.util.VersionInfo UNICODE_1_0;
field public static final android.icu.util.VersionInfo UNICODE_1_0_1;
field public static final android.icu.util.VersionInfo UNICODE_1_1_0;
diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp
index 3bb9929..d4d5871 100644
--- a/cmds/idmap2/Android.bp
+++ b/cmds/idmap2/Android.bp
@@ -18,6 +18,7 @@
tidy_checks: [
"modernize-*",
"-modernize-avoid-c-arrays",
+ "-modernize-use-trailing-return-type",
"android-*",
"misc-*",
"readability-*",
diff --git a/cmds/idmap2/tests/FileUtilsTests.cpp b/cmds/idmap2/tests/FileUtilsTests.cpp
index f4a306e..f55acee 100644
--- a/cmds/idmap2/tests/FileUtilsTests.cpp
+++ b/cmds/idmap2/tests/FileUtilsTests.cpp
@@ -15,6 +15,7 @@
*/
#include <dirent.h>
+#include <fcntl.h>
#include <set>
#include <string>
@@ -69,7 +70,7 @@
TEST(FileUtilsTests, ReadFile) {
int pipefd[2];
- ASSERT_EQ(pipe(pipefd), 0);
+ ASSERT_EQ(pipe2(pipefd, O_CLOEXEC), 0);
ASSERT_EQ(write(pipefd[1], "foobar", 6), 6);
close(pipefd[1]);
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 663cd55..96522f7 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -6875,6 +6875,9 @@
// Relative word (exclusive) index of the end of the smart selection.
optional int32 relative_suggested_word_end_index = 10;
+
+ // Name of source package.
+ optional string package_name = 11;
}
/**
@@ -6912,6 +6915,9 @@
// Time spent on generating links in ms.
optional int64 latency_millis = 10;
+
+ // Name of source package.
+ optional string package_name = 11;
}
/**
@@ -6943,6 +6949,9 @@
// The score of the first entity type.
optional float score = 8;
+
+ // Name of source package.
+ optional string package_name = 9;
}
/**
@@ -6971,6 +6980,9 @@
// Position of this action.
optional int32 action_index = 7;
+
+ // Name of source package.
+ optional string package_name = 8;
}
/**
diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt
index eb53b7c..9f48f8a 100644
--- a/config/hiddenapi-greylist.txt
+++ b/config/hiddenapi-greylist.txt
@@ -1174,214 +1174,11 @@
Lcom/android/internal/statusbar/IStatusBarService$Stub;-><init>()V
Lcom/android/internal/statusbar/IStatusBarService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/statusbar/IStatusBarService;
Lcom/android/internal/telecom/ITelecomService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telecom/ITelecomService;
-Lcom/android/internal/telephony/Call$State;->ALERTING:Lcom/android/internal/telephony/Call$State;
-Lcom/android/internal/telephony/Call$State;->DIALING:Lcom/android/internal/telephony/Call$State;
-Lcom/android/internal/telephony/Call$State;->DISCONNECTED:Lcom/android/internal/telephony/Call$State;
-Lcom/android/internal/telephony/Call$State;->DISCONNECTING:Lcom/android/internal/telephony/Call$State;
-Lcom/android/internal/telephony/Call$State;->HOLDING:Lcom/android/internal/telephony/Call$State;
-Lcom/android/internal/telephony/Call$State;->IDLE:Lcom/android/internal/telephony/Call$State;
-Lcom/android/internal/telephony/Call$State;->INCOMING:Lcom/android/internal/telephony/Call$State;
-Lcom/android/internal/telephony/Call$State;->values()[Lcom/android/internal/telephony/Call$State;
-Lcom/android/internal/telephony/Call$State;->WAITING:Lcom/android/internal/telephony/Call$State;
-Lcom/android/internal/telephony/Call;-><init>()V
-Lcom/android/internal/telephony/CallerInfoAsyncQuery$CallerInfoAsyncQueryHandler;-><init>(Lcom/android/internal/telephony/CallerInfoAsyncQuery;Landroid/content/Context;)V
-Lcom/android/internal/telephony/CallerInfoAsyncQuery$CookieWrapper;-><init>()V
-Lcom/android/internal/telephony/CallerInfoAsyncQuery;->release()V
-Lcom/android/internal/telephony/CallForwardInfo;-><init>()V
-Lcom/android/internal/telephony/CallTracker;-><init>()V
-Lcom/android/internal/telephony/cat/AppInterface$CommandType;->values()[Lcom/android/internal/telephony/cat/AppInterface$CommandType;
-Lcom/android/internal/telephony/cat/ResponseData;-><init>()V
-Lcom/android/internal/telephony/cat/ResultCode;->values()[Lcom/android/internal/telephony/cat/ResultCode;
-Lcom/android/internal/telephony/cat/RilMessageDecoder;->mCurrentRilMessage:Lcom/android/internal/telephony/cat/RilMessage;
-Lcom/android/internal/telephony/cat/RilMessageDecoder;->sendCmdForExecution(Lcom/android/internal/telephony/cat/RilMessage;)V
-Lcom/android/internal/telephony/cat/RilMessageDecoder;->sendStartDecodingMessageParams(Lcom/android/internal/telephony/cat/RilMessage;)V
-Lcom/android/internal/telephony/cat/ValueObject;-><init>()V
-Lcom/android/internal/telephony/cat/ValueParser;->retrieveDeviceIdentities(Lcom/android/internal/telephony/cat/ComprehensionTlv;)Lcom/android/internal/telephony/cat/DeviceIdentities;
-Lcom/android/internal/telephony/cdma/sms/BearerData$CodingException;-><init>(Ljava/lang/String;)V
-Lcom/android/internal/telephony/cdma/sms/BearerData$TimeStamp;-><init>()V
-Lcom/android/internal/telephony/cdma/sms/BearerData;-><init>()V
-Lcom/android/internal/telephony/cdma/sms/BearerData;->countAsciiSeptets(Ljava/lang/CharSequence;Z)I
-Lcom/android/internal/telephony/cdma/sms/BearerData;->decodeUserDataPayload(Lcom/android/internal/telephony/cdma/sms/UserData;Z)V
-Lcom/android/internal/telephony/cdma/sms/BearerData;->displayMode:I
-Lcom/android/internal/telephony/cdma/sms/BearerData;->encode(Lcom/android/internal/telephony/cdma/sms/BearerData;)[B
-Lcom/android/internal/telephony/cdma/sms/BearerData;->encode7bitAscii(Ljava/lang/String;Z)[B
-Lcom/android/internal/telephony/cdma/sms/BearerData;->getBitsForNumFields(II)I
-Lcom/android/internal/telephony/cdma/sms/BearerData;->hasUserDataHeader:Z
-Lcom/android/internal/telephony/cdma/sms/BearerData;->messageId:I
-Lcom/android/internal/telephony/cdma/sms/BearerData;->msgCenterTimeStamp:Lcom/android/internal/telephony/cdma/sms/BearerData$TimeStamp;
-Lcom/android/internal/telephony/cdma/sms/BearerData;->priority:I
-Lcom/android/internal/telephony/cdma/sms/BearerData;->priorityIndicatorSet:Z
-Lcom/android/internal/telephony/cdma/sms/BearerData;->userData:Lcom/android/internal/telephony/cdma/sms/UserData;
-Lcom/android/internal/telephony/cdma/sms/CdmaSmsAddress;-><init>()V
-Lcom/android/internal/telephony/cdma/sms/CdmaSmsAddress;->digitMode:I
-Lcom/android/internal/telephony/cdma/sms/CdmaSmsAddress;->numberMode:I
-Lcom/android/internal/telephony/cdma/sms/CdmaSmsAddress;->numberOfDigits:I
-Lcom/android/internal/telephony/cdma/sms/CdmaSmsAddress;->numberPlan:I
-Lcom/android/internal/telephony/cdma/sms/CdmaSmsAddress;->parse(Ljava/lang/String;)Lcom/android/internal/telephony/cdma/sms/CdmaSmsAddress;
-Lcom/android/internal/telephony/cdma/sms/SmsEnvelope;-><init>()V
-Lcom/android/internal/telephony/cdma/sms/SmsEnvelope;->bearerData:[B
-Lcom/android/internal/telephony/cdma/sms/SmsEnvelope;->serviceCategory:I
-Lcom/android/internal/telephony/cdma/sms/SmsEnvelope;->teleService:I
-Lcom/android/internal/telephony/cdma/sms/UserData;-><init>()V
-Lcom/android/internal/telephony/cdma/sms/UserData;->charToAscii:Landroid/util/SparseIntArray;
-Lcom/android/internal/telephony/cdma/sms/UserData;->msgEncoding:I
-Lcom/android/internal/telephony/cdma/sms/UserData;->msgEncodingSet:Z
-Lcom/android/internal/telephony/cdma/sms/UserData;->numFields:I
-Lcom/android/internal/telephony/cdma/sms/UserData;->payload:[B
-Lcom/android/internal/telephony/cdma/sms/UserData;->payloadStr:Ljava/lang/String;
-Lcom/android/internal/telephony/cdma/sms/UserData;->userDataHeader:Lcom/android/internal/telephony/SmsHeader;
-Lcom/android/internal/telephony/cdma/SmsMessage$SubmitPdu;-><init>()V
-Lcom/android/internal/telephony/cdma/SmsMessage;-><init>()V
-Lcom/android/internal/telephony/cdma/SmsMessage;->calculateLength(Ljava/lang/CharSequence;ZZ)Lcom/android/internal/telephony/GsmAlphabet$TextEncodingDetails;
-Lcom/android/internal/telephony/cdma/SmsMessage;->createFromEfRecord(I[B)Lcom/android/internal/telephony/cdma/SmsMessage;
-Lcom/android/internal/telephony/cdma/SmsMessage;->createFromPdu([B)Lcom/android/internal/telephony/cdma/SmsMessage;
-Lcom/android/internal/telephony/cdma/SmsMessage;->getIncomingSmsFingerprint()[B
-Lcom/android/internal/telephony/cdma/SmsMessage;->getMessageType()I
-Lcom/android/internal/telephony/cdma/SmsMessage;->getNextMessageId()I
-Lcom/android/internal/telephony/cdma/SmsMessage;->getNumOfVoicemails()I
-Lcom/android/internal/telephony/cdma/SmsMessage;->getSubmitPdu(Ljava/lang/String;Lcom/android/internal/telephony/cdma/sms/UserData;Z)Lcom/android/internal/telephony/cdma/SmsMessage$SubmitPdu;
-Lcom/android/internal/telephony/cdma/SmsMessage;->getSubmitPdu(Ljava/lang/String;Lcom/android/internal/telephony/cdma/sms/UserData;ZI)Lcom/android/internal/telephony/cdma/SmsMessage$SubmitPdu;
-Lcom/android/internal/telephony/cdma/SmsMessage;->getSubmitPdu(Ljava/lang/String;Ljava/lang/String;I[BZ)Lcom/android/internal/telephony/cdma/SmsMessage$SubmitPdu;
-Lcom/android/internal/telephony/cdma/SmsMessage;->getSubmitPdu(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZLcom/android/internal/telephony/SmsHeader;)Lcom/android/internal/telephony/cdma/SmsMessage$SubmitPdu;
-Lcom/android/internal/telephony/cdma/SmsMessage;->getSubmitPdu(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZLcom/android/internal/telephony/SmsHeader;I)Lcom/android/internal/telephony/cdma/SmsMessage$SubmitPdu;
-Lcom/android/internal/telephony/cdma/SmsMessage;->getTeleService()I
-Lcom/android/internal/telephony/cdma/SmsMessage;->isStatusReportMessage()Z
-Lcom/android/internal/telephony/cdma/SmsMessage;->mBearerData:Lcom/android/internal/telephony/cdma/sms/BearerData;
-Lcom/android/internal/telephony/cdma/SmsMessage;->mEnvelope:Lcom/android/internal/telephony/cdma/sms/SmsEnvelope;
-Lcom/android/internal/telephony/cdma/SmsMessage;->parseSms()V
-Lcom/android/internal/telephony/cdma/SmsMessage;->privateGetSubmitPdu(Ljava/lang/String;ZLcom/android/internal/telephony/cdma/sms/UserData;)Lcom/android/internal/telephony/cdma/SmsMessage$SubmitPdu;
-Lcom/android/internal/telephony/DctConstants$Activity;->DATAIN:Lcom/android/internal/telephony/DctConstants$Activity;
-Lcom/android/internal/telephony/DctConstants$Activity;->DATAINANDOUT:Lcom/android/internal/telephony/DctConstants$Activity;
-Lcom/android/internal/telephony/DctConstants$Activity;->DATAOUT:Lcom/android/internal/telephony/DctConstants$Activity;
-Lcom/android/internal/telephony/DctConstants$Activity;->DORMANT:Lcom/android/internal/telephony/DctConstants$Activity;
-Lcom/android/internal/telephony/DctConstants$Activity;->values()[Lcom/android/internal/telephony/DctConstants$Activity;
-Lcom/android/internal/telephony/DctConstants$State;->CONNECTED:Lcom/android/internal/telephony/DctConstants$State;
-Lcom/android/internal/telephony/DctConstants$State;->CONNECTING:Lcom/android/internal/telephony/DctConstants$State;
-Lcom/android/internal/telephony/DctConstants$State;->DISCONNECTING:Lcom/android/internal/telephony/DctConstants$State;
-Lcom/android/internal/telephony/DctConstants$State;->FAILED:Lcom/android/internal/telephony/DctConstants$State;
-Lcom/android/internal/telephony/DctConstants$State;->IDLE:Lcom/android/internal/telephony/DctConstants$State;
-Lcom/android/internal/telephony/DctConstants$State;->RETRYING:Lcom/android/internal/telephony/DctConstants$State;
-Lcom/android/internal/telephony/DctConstants$State;->values()[Lcom/android/internal/telephony/DctConstants$State;
-Lcom/android/internal/telephony/DriverCall$State;->values()[Lcom/android/internal/telephony/DriverCall$State;
-Lcom/android/internal/telephony/gsm/GsmCellBroadcastHandler$SmsCbConcatInfo;-><init>(Lcom/android/internal/telephony/gsm/SmsCbHeader;Landroid/telephony/SmsCbLocation;)V
-Lcom/android/internal/telephony/gsm/GsmCellBroadcastHandler$SmsCbConcatInfo;->matchesLocation(Ljava/lang/String;II)Z
-Lcom/android/internal/telephony/gsm/GsmCellBroadcastHandler;->mSmsCbPageMap:Ljava/util/HashMap;
-Lcom/android/internal/telephony/gsm/GsmInboundSmsHandler;->acknowledgeLastIncomingSms(ZILandroid/os/Message;)V
-Lcom/android/internal/telephony/gsm/GsmMmiCode;-><init>(Lcom/android/internal/telephony/GsmCdmaPhone;Lcom/android/internal/telephony/uicc/UiccCardApplication;)V
-Lcom/android/internal/telephony/gsm/GsmMmiCode;->getCLIRMode()I
-Lcom/android/internal/telephony/gsm/GsmMmiCode;->getScString()Ljava/lang/CharSequence;
-Lcom/android/internal/telephony/gsm/GsmMmiCode;->isActivate()Z
-Lcom/android/internal/telephony/gsm/GsmMmiCode;->isDeactivate()Z
-Lcom/android/internal/telephony/gsm/GsmMmiCode;->isErasure()Z
-Lcom/android/internal/telephony/gsm/GsmMmiCode;->isInterrogate()Z
-Lcom/android/internal/telephony/gsm/GsmMmiCode;->isRegister()Z
-Lcom/android/internal/telephony/gsm/GsmMmiCode;->isServiceCodeCallBarring(Ljava/lang/String;)Z
-Lcom/android/internal/telephony/gsm/GsmMmiCode;->isServiceCodeCallForwarding(Ljava/lang/String;)Z
-Lcom/android/internal/telephony/gsm/GsmMmiCode;->isTemporaryModeCLIR()Z
-Lcom/android/internal/telephony/gsm/GsmMmiCode;->makeEmptyNull(Ljava/lang/String;)Ljava/lang/String;
-Lcom/android/internal/telephony/gsm/GsmMmiCode;->mContext:Landroid/content/Context;
-Lcom/android/internal/telephony/gsm/GsmMmiCode;->mDialingNumber:Ljava/lang/String;
-Lcom/android/internal/telephony/gsm/GsmMmiCode;->mIccRecords:Lcom/android/internal/telephony/uicc/IccRecords;
-Lcom/android/internal/telephony/gsm/GsmMmiCode;->mPhone:Lcom/android/internal/telephony/GsmCdmaPhone;
-Lcom/android/internal/telephony/gsm/GsmMmiCode;->mSc:Ljava/lang/String;
-Lcom/android/internal/telephony/gsm/GsmMmiCode;->mSia:Ljava/lang/String;
-Lcom/android/internal/telephony/gsm/GsmMmiCode;->mSib:Ljava/lang/String;
-Lcom/android/internal/telephony/gsm/GsmMmiCode;->mSic:Ljava/lang/String;
-Lcom/android/internal/telephony/gsm/GsmMmiCode;->newFromDialString(Ljava/lang/String;Lcom/android/internal/telephony/GsmCdmaPhone;Lcom/android/internal/telephony/uicc/UiccCardApplication;)Lcom/android/internal/telephony/gsm/GsmMmiCode;
-Lcom/android/internal/telephony/gsm/GsmMmiCode;->processCode()V
-Lcom/android/internal/telephony/gsm/GsmMmiCode;->siToServiceClass(Ljava/lang/String;)I
-Lcom/android/internal/telephony/gsm/GsmMmiCode;->sPatternSuppService:Ljava/util/regex/Pattern;
-Lcom/android/internal/telephony/gsm/GsmSmsAddress;-><init>([BII)V
-Lcom/android/internal/telephony/gsm/GsmSmsAddress;->isCphsVoiceMessageClear()Z
-Lcom/android/internal/telephony/gsm/GsmSmsAddress;->isCphsVoiceMessageSet()Z
-Lcom/android/internal/telephony/gsm/GsmSMSDispatcher;->getFormat()Ljava/lang/String;
-Lcom/android/internal/telephony/gsm/GsmSMSDispatcher;->mGsmInboundSmsHandler:Lcom/android/internal/telephony/gsm/GsmInboundSmsHandler;
-Lcom/android/internal/telephony/gsm/GsmSMSDispatcher;->sendSms(Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;)V
-Lcom/android/internal/telephony/gsm/SimTlv;-><init>([BII)V
-Lcom/android/internal/telephony/gsm/SimTlv;->getData()[B
-Lcom/android/internal/telephony/gsm/SimTlv;->getTag()I
-Lcom/android/internal/telephony/gsm/SimTlv;->isValidObject()Z
-Lcom/android/internal/telephony/gsm/SimTlv;->mHasValidTlvObject:Z
-Lcom/android/internal/telephony/gsm/SimTlv;->nextObject()Z
-Lcom/android/internal/telephony/gsm/SmsCbHeader;-><init>([B)V
-Lcom/android/internal/telephony/gsm/SmsCbHeader;->getGeographicalScope()I
-Lcom/android/internal/telephony/gsm/SmsCbHeader;->getNumberOfPages()I
-Lcom/android/internal/telephony/gsm/SmsCbHeader;->getPageIndex()I
-Lcom/android/internal/telephony/gsm/SmsCbHeader;->getSerialNumber()I
-Lcom/android/internal/telephony/gsm/SmsCbHeader;->getServiceCategory()I
-Lcom/android/internal/telephony/gsm/SmsCbHeader;->mMessageIdentifier:I
-Lcom/android/internal/telephony/gsm/SmsMessage$PduParser;-><init>([B)V
-Lcom/android/internal/telephony/gsm/SmsMessage$PduParser;->getByte()I
-Lcom/android/internal/telephony/gsm/SmsMessage$PduParser;->getUserData()[B
-Lcom/android/internal/telephony/gsm/SmsMessage$PduParser;->getUserDataUCS2(I)Ljava/lang/String;
-Lcom/android/internal/telephony/gsm/SmsMessage$PduParser;->mCur:I
-Lcom/android/internal/telephony/gsm/SmsMessage$PduParser;->mPdu:[B
-Lcom/android/internal/telephony/gsm/SmsMessage$PduParser;->mUserDataSeptetPadding:I
-Lcom/android/internal/telephony/gsm/SmsMessage$SubmitPdu;-><init>()V
-Lcom/android/internal/telephony/gsm/SmsMessage;-><init>()V
-Lcom/android/internal/telephony/gsm/SmsMessage;->calculateLength(Ljava/lang/CharSequence;Z)Lcom/android/internal/telephony/GsmAlphabet$TextEncodingDetails;
-Lcom/android/internal/telephony/gsm/SmsMessage;->createFromEfRecord(I[B)Lcom/android/internal/telephony/gsm/SmsMessage;
-Lcom/android/internal/telephony/gsm/SmsMessage;->createFromPdu([B)Lcom/android/internal/telephony/gsm/SmsMessage;
-Lcom/android/internal/telephony/gsm/SmsMessage;->encodeUCS2(Ljava/lang/String;[B)[B
-Lcom/android/internal/telephony/gsm/SmsMessage;->getStatus()I
-Lcom/android/internal/telephony/gsm/SmsMessage;->getSubmitPdu(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)Lcom/android/internal/telephony/gsm/SmsMessage$SubmitPdu;
-Lcom/android/internal/telephony/gsm/SmsMessage;->getSubmitPdu(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZI)Lcom/android/internal/telephony/gsm/SmsMessage$SubmitPdu;
-Lcom/android/internal/telephony/gsm/SmsMessage;->getSubmitPdu(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z[B)Lcom/android/internal/telephony/gsm/SmsMessage$SubmitPdu;
-Lcom/android/internal/telephony/gsm/SmsMessage;->getSubmitPdu(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z[BIII)Lcom/android/internal/telephony/gsm/SmsMessage$SubmitPdu;
-Lcom/android/internal/telephony/gsm/SmsMessage;->getSubmitPdu(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z[BIIII)Lcom/android/internal/telephony/gsm/SmsMessage$SubmitPdu;
-Lcom/android/internal/telephony/gsm/SmsMessage;->getSubmitPduHead(Ljava/lang/String;Ljava/lang/String;BZLcom/android/internal/telephony/gsm/SmsMessage$SubmitPdu;)Ljava/io/ByteArrayOutputStream;
-Lcom/android/internal/telephony/gsm/SmsMessage;->isMWIClearMessage()Z
-Lcom/android/internal/telephony/gsm/SmsMessage;->isMwiDontStore()Z
-Lcom/android/internal/telephony/gsm/SmsMessage;->isMWISetMessage()Z
-Lcom/android/internal/telephony/gsm/SmsMessage;->isStatusReportMessage()Z
-Lcom/android/internal/telephony/gsm/UsimPhoneBookManager;->loadEfFilesFromUsim()Ljava/util/ArrayList;
-Lcom/android/internal/telephony/gsm/UsimPhoneBookManager;->log(Ljava/lang/String;)V
-Lcom/android/internal/telephony/gsm/UsimPhoneBookManager;->mFh:Lcom/android/internal/telephony/uicc/IccFileHandler;
-Lcom/android/internal/telephony/gsm/UsimPhoneBookManager;->mLock:Ljava/lang/Object;
-Lcom/android/internal/telephony/gsm/UsimPhoneBookManager;->mPhoneBookRecords:Ljava/util/ArrayList;
-Lcom/android/internal/telephony/gsm/UsimPhoneBookManager;->reset()V
-Lcom/android/internal/telephony/GsmAlphabet$TextEncodingDetails;-><init>()V
-Lcom/android/internal/telephony/GsmCdmaConnection$MyHandler;-><init>(Lcom/android/internal/telephony/GsmCdmaConnection;Landroid/os/Looper;)V
-Lcom/android/internal/telephony/IccCardConstants$State;->ABSENT:Lcom/android/internal/telephony/IccCardConstants$State;
-Lcom/android/internal/telephony/IccCardConstants$State;->CARD_IO_ERROR:Lcom/android/internal/telephony/IccCardConstants$State;
-Lcom/android/internal/telephony/IccCardConstants$State;->NETWORK_LOCKED:Lcom/android/internal/telephony/IccCardConstants$State;
-Lcom/android/internal/telephony/IccCardConstants$State;->NOT_READY:Lcom/android/internal/telephony/IccCardConstants$State;
-Lcom/android/internal/telephony/IccCardConstants$State;->PERM_DISABLED:Lcom/android/internal/telephony/IccCardConstants$State;
-Lcom/android/internal/telephony/IccCardConstants$State;->PIN_REQUIRED:Lcom/android/internal/telephony/IccCardConstants$State;
-Lcom/android/internal/telephony/IccCardConstants$State;->PUK_REQUIRED:Lcom/android/internal/telephony/IccCardConstants$State;
-Lcom/android/internal/telephony/IccCardConstants$State;->READY:Lcom/android/internal/telephony/IccCardConstants$State;
-Lcom/android/internal/telephony/IccCardConstants$State;->UNKNOWN:Lcom/android/internal/telephony/IccCardConstants$State;
-Lcom/android/internal/telephony/IccCardConstants$State;->values()[Lcom/android/internal/telephony/IccCardConstants$State;
-Lcom/android/internal/telephony/IccProvider;-><init>()V
Lcom/android/internal/telephony/IIccPhoneBook$Stub$Proxy;->mRemote:Landroid/os/IBinder;
Lcom/android/internal/telephony/IIccPhoneBook$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/IIccPhoneBook;
-Lcom/android/internal/telephony/IIccPhoneBook;->getAdnRecordsInEf(I)Ljava/util/List;
-Lcom/android/internal/telephony/IIccPhoneBook;->getAdnRecordsInEfForSubscriber(II)Ljava/util/List;
-Lcom/android/internal/telephony/IIccPhoneBook;->getAdnRecordsSize(I)[I
-Lcom/android/internal/telephony/IIccPhoneBook;->getAdnRecordsSizeForSubscriber(II)[I
-Lcom/android/internal/telephony/IIccPhoneBook;->updateAdnRecordsInEfBySearch(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z
Lcom/android/internal/telephony/IMms$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/IMms;
-Lcom/android/internal/telephony/imsphone/ImsExternalCallTracker$ExternalCallStateListener;-><init>(Lcom/android/internal/telephony/imsphone/ImsExternalCallTracker;)V
-Lcom/android/internal/telephony/imsphone/ImsExternalCallTracker$ExternalConnectionListener;-><init>(Lcom/android/internal/telephony/imsphone/ImsExternalCallTracker;)V
-Lcom/android/internal/telephony/imsphone/ImsPhone;->notifyCallForwardingIndicator()V
-Lcom/android/internal/telephony/imsphone/ImsPhone;->notifyPreciseCallStateChanged()V
-Lcom/android/internal/telephony/imsphone/ImsPhoneCall;->getImsCall()Lcom/android/ims/ImsCall;
-Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->findConnection(Lcom/android/ims/ImsCall;)Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;
-Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->getEcbmInterface()Lcom/android/ims/ImsEcbm;
-Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mCallExpectedToResume:Lcom/android/ims/ImsCall;
-Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mImsCallListener:Lcom/android/ims/ImsCall$Listener;
-Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mImsManager:Lcom/android/ims/ImsManager;
-Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mUssdSession:Lcom/android/ims/ImsCall;
-Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->processCallStateChange(Lcom/android/ims/ImsCall;Lcom/android/internal/telephony/Call$State;I)V
-Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->processCallStateChange(Lcom/android/ims/ImsCall;Lcom/android/internal/telephony/Call$State;IZ)V
-Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->setVideoCallProvider(Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;Lcom/android/ims/ImsCall;)V
-Lcom/android/internal/telephony/imsphone/ImsPhoneConnection$MyHandler;-><init>(Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;Landroid/os/Looper;)V
-Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->mImsCall:Lcom/android/ims/ImsCall;
-Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->update(Lcom/android/ims/ImsCall;Lcom/android/internal/telephony/Call$State;)Z
-Lcom/android/internal/telephony/InboundSmsHandler$SmsBroadcastReceiver;-><init>(Lcom/android/internal/telephony/InboundSmsHandler;Lcom/android/internal/telephony/InboundSmsTracker;)V
Lcom/android/internal/telephony/IPhoneStateListener$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/IPhoneStateListener;
Lcom/android/internal/telephony/IPhoneSubInfo$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Lcom/android/internal/telephony/IPhoneSubInfo$Stub$Proxy;->getDeviceId(Ljava/lang/String;)Ljava/lang/String;
Lcom/android/internal/telephony/IPhoneSubInfo$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/IPhoneSubInfo;
Lcom/android/internal/telephony/IPhoneSubInfo$Stub;->TRANSACTION_getDeviceId:I
Lcom/android/internal/telephony/ISms$Stub;-><init>()V
@@ -1389,8 +1186,6 @@
Lcom/android/internal/telephony/ISub$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Lcom/android/internal/telephony/ISub$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/ISub;
Lcom/android/internal/telephony/ITelephony$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->getDeviceId(Ljava/lang/String;)Ljava/lang/String;
-Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->isRadioOn(Ljava/lang/String;)Z
Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->mRemote:Landroid/os/IBinder;
Lcom/android/internal/telephony/ITelephony$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/ITelephony;
Lcom/android/internal/telephony/ITelephony$Stub;->DESCRIPTOR:Ljava/lang/String;
@@ -1400,82 +1195,6 @@
Lcom/android/internal/telephony/ITelephonyRegistry$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Lcom/android/internal/telephony/ITelephonyRegistry$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/ITelephonyRegistry;
Lcom/android/internal/telephony/IWapPushManager$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/IWapPushManager;
-Lcom/android/internal/telephony/PhoneConstants$DataState;->CONNECTED:Lcom/android/internal/telephony/PhoneConstants$DataState;
-Lcom/android/internal/telephony/PhoneConstants$DataState;->CONNECTING:Lcom/android/internal/telephony/PhoneConstants$DataState;
-Lcom/android/internal/telephony/PhoneConstants$DataState;->DISCONNECTED:Lcom/android/internal/telephony/PhoneConstants$DataState;
-Lcom/android/internal/telephony/PhoneConstants$DataState;->SUSPENDED:Lcom/android/internal/telephony/PhoneConstants$DataState;
-Lcom/android/internal/telephony/PhoneConstants$DataState;->values()[Lcom/android/internal/telephony/PhoneConstants$DataState;
-Lcom/android/internal/telephony/PhoneConstants$State;->IDLE:Lcom/android/internal/telephony/PhoneConstants$State;
-Lcom/android/internal/telephony/PhoneConstants$State;->OFFHOOK:Lcom/android/internal/telephony/PhoneConstants$State;
-Lcom/android/internal/telephony/PhoneConstants$State;->RINGING:Lcom/android/internal/telephony/PhoneConstants$State;
-Lcom/android/internal/telephony/PhoneConstants$State;->values()[Lcom/android/internal/telephony/PhoneConstants$State;
-Lcom/android/internal/telephony/PhoneConstants;->PRESENTATION_ALLOWED:I
-Lcom/android/internal/telephony/PhoneConstants;->PRESENTATION_PAYPHONE:I
-Lcom/android/internal/telephony/PhoneConstants;->PRESENTATION_RESTRICTED:I
-Lcom/android/internal/telephony/PhoneConstants;->PRESENTATION_UNKNOWN:I
-Lcom/android/internal/telephony/RILConstants;->PREFERRED_NETWORK_MODE:I
-Lcom/android/internal/telephony/sip/SipPhone$SipCall;->hold()V
-Lcom/android/internal/telephony/sip/SipPhone$SipCall;->switchWith(Lcom/android/internal/telephony/sip/SipPhone$SipCall;)V
-Lcom/android/internal/telephony/sip/SipPhone$SipCall;->unhold()V
-Lcom/android/internal/telephony/sip/SipPhone;->log(Ljava/lang/String;)V
-Lcom/android/internal/telephony/sip/SipPhone;->loge(Ljava/lang/String;)V
-Lcom/android/internal/telephony/sip/SipPhone;->mBackgroundCall:Lcom/android/internal/telephony/sip/SipPhone$SipCall;
-Lcom/android/internal/telephony/sip/SipPhone;->mForegroundCall:Lcom/android/internal/telephony/sip/SipPhone$SipCall;
-Lcom/android/internal/telephony/Sms7BitEncodingTranslator;->DBG:Z
-Lcom/android/internal/telephony/Sms7BitEncodingTranslator;->mTranslationTableCDMA:Landroid/util/SparseIntArray;
-Lcom/android/internal/telephony/Sms7BitEncodingTranslator;->mTranslationTableCommon:Landroid/util/SparseIntArray;
-Lcom/android/internal/telephony/Sms7BitEncodingTranslator;->mTranslationTableGSM:Landroid/util/SparseIntArray;
-Lcom/android/internal/telephony/SmsApplication$SmsApplicationData;->mApplicationName:Ljava/lang/String;
-Lcom/android/internal/telephony/SmsApplication;->configurePreferredActivity(Landroid/content/pm/PackageManager;Landroid/content/ComponentName;I)V
-Lcom/android/internal/telephony/SmsApplication;->getApplicationCollection(Landroid/content/Context;)Ljava/util/Collection;
-Lcom/android/internal/telephony/SmsApplication;->getDefaultMmsApplication(Landroid/content/Context;Z)Landroid/content/ComponentName;
-Lcom/android/internal/telephony/SmsApplication;->getDefaultRespondViaMessageApplication(Landroid/content/Context;Z)Landroid/content/ComponentName;
-Lcom/android/internal/telephony/SmsApplication;->getDefaultSmsApplication(Landroid/content/Context;Z)Landroid/content/ComponentName;
-Lcom/android/internal/telephony/SmsApplication;->getSmsApplicationData(Ljava/lang/String;Landroid/content/Context;)Lcom/android/internal/telephony/SmsApplication$SmsApplicationData;
-Lcom/android/internal/telephony/SmsApplication;->isDefaultSmsApplication(Landroid/content/Context;Ljava/lang/String;)Z
-Lcom/android/internal/telephony/SmsApplication;->setDefaultApplication(Ljava/lang/String;Landroid/content/Context;)V
-Lcom/android/internal/telephony/SmsApplication;->shouldWriteMessageForPackage(Ljava/lang/String;Landroid/content/Context;)Z
-Lcom/android/internal/telephony/SMSDispatcher$DataSmsSender;-><init>(Lcom/android/internal/telephony/SMSDispatcher;Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;)V
-Lcom/android/internal/telephony/SMSDispatcher$MultipartSmsSender;-><init>(Lcom/android/internal/telephony/SMSDispatcher;Ljava/util/ArrayList;[Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;)V
-Lcom/android/internal/telephony/SMSDispatcher$MultipartSmsSenderCallback;-><init>(Lcom/android/internal/telephony/SMSDispatcher;Lcom/android/internal/telephony/SMSDispatcher$MultipartSmsSender;)V
-Lcom/android/internal/telephony/SMSDispatcher$SmsSenderCallback;-><init>(Lcom/android/internal/telephony/SMSDispatcher;Lcom/android/internal/telephony/SMSDispatcher$SmsSender;)V
-Lcom/android/internal/telephony/SMSDispatcher$TextSmsSender;-><init>(Lcom/android/internal/telephony/SMSDispatcher;Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;)V
-Lcom/android/internal/telephony/SmsHeader$ConcatRef;-><init>()V
-Lcom/android/internal/telephony/SmsHeader$PortAddrs;-><init>()V
-Lcom/android/internal/telephony/SmsMessageBase;-><init>()V
-Lcom/android/internal/telephony/TelephonyProperties;->PROPERTY_ICC_OPERATOR_NUMERIC:Ljava/lang/String;
-Lcom/android/internal/telephony/test/InterpreterEx;-><init>(Ljava/lang/String;)V
-Lcom/android/internal/telephony/test/SimulatedCommands;->acceptCall(Landroid/os/Message;)V
-Lcom/android/internal/telephony/test/SimulatedCommands;->mDcSuccess:Z
-Lcom/android/internal/telephony/test/SimulatedCommands;->resultFail(Landroid/os/Message;Ljava/lang/Object;Ljava/lang/Throwable;)V
-Lcom/android/internal/telephony/test/SimulatedCommands;->resultSuccess(Landroid/os/Message;Ljava/lang/Object;)V
-Lcom/android/internal/telephony/test/SimulatedCommands;->simulatedCallState:Lcom/android/internal/telephony/test/SimulatedGsmCallState;
-Lcom/android/internal/telephony/test/SimulatedCommands;->unimplemented(Landroid/os/Message;)V
-Lcom/android/internal/telephony/test/SimulatedCommandsVerifier;->getInstance()Lcom/android/internal/telephony/test/SimulatedCommandsVerifier;
-Lcom/android/internal/telephony/test/SimulatedCommandsVerifier;->setCallForward(IIILjava/lang/String;ILandroid/os/Message;)V
-Lcom/android/internal/telephony/test/SimulatedGsmCallState;->conference()Z
-Lcom/android/internal/telephony/test/SimulatedGsmCallState;->onChld(CC)Z
-Lcom/android/internal/telephony/test/SimulatedGsmCallState;->releaseActiveAcceptHeldOrWaiting()Z
-Lcom/android/internal/telephony/test/SimulatedGsmCallState;->releaseHeldOrUDUB()Z
-Lcom/android/internal/telephony/test/SimulatedGsmCallState;->separateCall(I)Z
-Lcom/android/internal/telephony/test/SimulatedGsmCallState;->switchActiveAndHeldOrWaiting()Z
-Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;->values()[Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;
-Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;->values()[Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;
-Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;->values()[Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;
-Lcom/android/internal/telephony/uicc/IccCardApplicationStatus;-><init>()V
-Lcom/android/internal/telephony/uicc/IccRefreshResponse;-><init>()V
-Lcom/android/internal/telephony/uicc/IccUtils;->adnStringFieldToString([BII)Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/IccUtils;->bcdToString([BII)Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/IccUtils;->bytesToHexString([B)Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/IccUtils;->cdmaBcdByteToInt(B)I
-Lcom/android/internal/telephony/uicc/IccUtils;->cdmaBcdToString([BII)Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/IccUtils;->gsmBcdByteToInt(B)I
-Lcom/android/internal/telephony/uicc/IccUtils;->hexCharToInt(C)I
-Lcom/android/internal/telephony/uicc/IccUtils;->hexStringToBytes(Ljava/lang/String;)[B
-Lcom/android/internal/telephony/uicc/IccUtils;->networkNameToString([BII)Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/IccUtils;->parseToBnW([BI)Landroid/graphics/Bitmap;
-Lcom/android/internal/telephony/uicc/IccUtils;->parseToRGB([BIZ)Landroid/graphics/Bitmap;
-Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState;->values()[Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState;
Lcom/android/internal/textservice/ITextServicesManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Lcom/android/internal/util/MemInfoReader;-><init>()V
Lcom/android/internal/view/IInputMethodManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
@@ -1488,283 +1207,5 @@
Lcom/android/server/ResettableTimeout$T;-><init>(Lcom/android/server/ResettableTimeout;)V
Lcom/google/android/gles_jni/EGLImpl;-><init>()V
Lcom/google/android/gles_jni/GLImpl;-><init>()V
-Lcom/google/android/mms/ContentType;->getAudioTypes()Ljava/util/ArrayList;
-Lcom/google/android/mms/ContentType;->getImageTypes()Ljava/util/ArrayList;
-Lcom/google/android/mms/ContentType;->getVideoTypes()Ljava/util/ArrayList;
-Lcom/google/android/mms/ContentType;->isAudioType(Ljava/lang/String;)Z
-Lcom/google/android/mms/ContentType;->isDrmType(Ljava/lang/String;)Z
-Lcom/google/android/mms/ContentType;->isImageType(Ljava/lang/String;)Z
-Lcom/google/android/mms/ContentType;->isSupportedAudioType(Ljava/lang/String;)Z
-Lcom/google/android/mms/ContentType;->isSupportedImageType(Ljava/lang/String;)Z
-Lcom/google/android/mms/ContentType;->isSupportedType(Ljava/lang/String;)Z
-Lcom/google/android/mms/ContentType;->isSupportedVideoType(Ljava/lang/String;)Z
-Lcom/google/android/mms/ContentType;->isTextType(Ljava/lang/String;)Z
-Lcom/google/android/mms/ContentType;->isVideoType(Ljava/lang/String;)Z
-Lcom/google/android/mms/InvalidHeaderValueException;-><init>(Ljava/lang/String;)V
-Lcom/google/android/mms/MmsException;-><init>()V
-Lcom/google/android/mms/MmsException;-><init>(Ljava/lang/String;)V
-Lcom/google/android/mms/MmsException;-><init>(Ljava/lang/String;Ljava/lang/Throwable;)V
-Lcom/google/android/mms/MmsException;-><init>(Ljava/lang/Throwable;)V
-Lcom/google/android/mms/pdu/AcknowledgeInd;-><init>(I[B)V
-Lcom/google/android/mms/pdu/AcknowledgeInd;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V
-Lcom/google/android/mms/pdu/AcknowledgeInd;->setReportAllowed(I)V
-Lcom/google/android/mms/pdu/AcknowledgeInd;->setTransactionId([B)V
-Lcom/google/android/mms/pdu/Base64;->decodeBase64([B)[B
-Lcom/google/android/mms/pdu/CharacterSets;->getMibEnumValue(Ljava/lang/String;)I
-Lcom/google/android/mms/pdu/CharacterSets;->getMimeName(I)Ljava/lang/String;
-Lcom/google/android/mms/pdu/DeliveryInd;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V
-Lcom/google/android/mms/pdu/DeliveryInd;->getDate()J
-Lcom/google/android/mms/pdu/DeliveryInd;->getMessageId()[B
-Lcom/google/android/mms/pdu/DeliveryInd;->getStatus()I
-Lcom/google/android/mms/pdu/DeliveryInd;->getTo()[Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/EncodedStringValue;-><init>(I[B)V
-Lcom/google/android/mms/pdu/EncodedStringValue;-><init>(Ljava/lang/String;)V
-Lcom/google/android/mms/pdu/EncodedStringValue;-><init>([B)V
-Lcom/google/android/mms/pdu/EncodedStringValue;->appendTextString([B)V
-Lcom/google/android/mms/pdu/EncodedStringValue;->concat([Lcom/google/android/mms/pdu/EncodedStringValue;)Ljava/lang/String;
-Lcom/google/android/mms/pdu/EncodedStringValue;->copy(Lcom/google/android/mms/pdu/EncodedStringValue;)Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/EncodedStringValue;->encodeStrings([Ljava/lang/String;)[Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/EncodedStringValue;->extract(Ljava/lang/String;)[Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/EncodedStringValue;->getCharacterSet()I
-Lcom/google/android/mms/pdu/EncodedStringValue;->getString()Ljava/lang/String;
-Lcom/google/android/mms/pdu/EncodedStringValue;->getTextString()[B
-Lcom/google/android/mms/pdu/EncodedStringValue;->setCharacterSet(I)V
-Lcom/google/android/mms/pdu/EncodedStringValue;->setTextString([B)V
-Lcom/google/android/mms/pdu/GenericPdu;-><init>()V
-Lcom/google/android/mms/pdu/GenericPdu;->getFrom()Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/GenericPdu;->getMessageType()I
-Lcom/google/android/mms/pdu/GenericPdu;->getPduHeaders()Lcom/google/android/mms/pdu/PduHeaders;
-Lcom/google/android/mms/pdu/GenericPdu;->mPduHeaders:Lcom/google/android/mms/pdu/PduHeaders;
-Lcom/google/android/mms/pdu/GenericPdu;->setFrom(Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/GenericPdu;->setMessageType(I)V
-Lcom/google/android/mms/pdu/MultimediaMessagePdu;-><init>()V
-Lcom/google/android/mms/pdu/MultimediaMessagePdu;-><init>(Lcom/google/android/mms/pdu/PduHeaders;Lcom/google/android/mms/pdu/PduBody;)V
-Lcom/google/android/mms/pdu/MultimediaMessagePdu;->addTo(Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/MultimediaMessagePdu;->getBody()Lcom/google/android/mms/pdu/PduBody;
-Lcom/google/android/mms/pdu/MultimediaMessagePdu;->getDate()J
-Lcom/google/android/mms/pdu/MultimediaMessagePdu;->getPriority()I
-Lcom/google/android/mms/pdu/MultimediaMessagePdu;->getSubject()Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/MultimediaMessagePdu;->getTo()[Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/MultimediaMessagePdu;->setBody(Lcom/google/android/mms/pdu/PduBody;)V
-Lcom/google/android/mms/pdu/MultimediaMessagePdu;->setDate(J)V
-Lcom/google/android/mms/pdu/MultimediaMessagePdu;->setPriority(I)V
-Lcom/google/android/mms/pdu/MultimediaMessagePdu;->setSubject(Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/NotificationInd;-><init>()V
-Lcom/google/android/mms/pdu/NotificationInd;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V
-Lcom/google/android/mms/pdu/NotificationInd;->getContentClass()I
-Lcom/google/android/mms/pdu/NotificationInd;->getContentLocation()[B
-Lcom/google/android/mms/pdu/NotificationInd;->getDeliveryReport()I
-Lcom/google/android/mms/pdu/NotificationInd;->getExpiry()J
-Lcom/google/android/mms/pdu/NotificationInd;->getFrom()Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/NotificationInd;->getMessageClass()[B
-Lcom/google/android/mms/pdu/NotificationInd;->getMessageSize()J
-Lcom/google/android/mms/pdu/NotificationInd;->getSubject()Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/NotificationInd;->getTransactionId()[B
-Lcom/google/android/mms/pdu/NotificationInd;->setContentClass(I)V
-Lcom/google/android/mms/pdu/NotificationInd;->setContentLocation([B)V
-Lcom/google/android/mms/pdu/NotificationInd;->setDeliveryReport(I)V
-Lcom/google/android/mms/pdu/NotificationInd;->setExpiry(J)V
-Lcom/google/android/mms/pdu/NotificationInd;->setFrom(Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/NotificationInd;->setMessageClass([B)V
-Lcom/google/android/mms/pdu/NotificationInd;->setMessageSize(J)V
-Lcom/google/android/mms/pdu/NotificationInd;->setSubject(Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/NotificationInd;->setTransactionId([B)V
-Lcom/google/android/mms/pdu/NotifyRespInd;-><init>(I[BI)V
-Lcom/google/android/mms/pdu/NotifyRespInd;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V
-Lcom/google/android/mms/pdu/NotifyRespInd;->setReportAllowed(I)V
-Lcom/google/android/mms/pdu/NotifyRespInd;->setStatus(I)V
-Lcom/google/android/mms/pdu/NotifyRespInd;->setTransactionId([B)V
-Lcom/google/android/mms/pdu/PduBody;-><init>()V
-Lcom/google/android/mms/pdu/PduBody;->addPart(ILcom/google/android/mms/pdu/PduPart;)V
-Lcom/google/android/mms/pdu/PduBody;->addPart(Lcom/google/android/mms/pdu/PduPart;)Z
-Lcom/google/android/mms/pdu/PduBody;->getPart(I)Lcom/google/android/mms/pdu/PduPart;
-Lcom/google/android/mms/pdu/PduBody;->getPartByContentId(Ljava/lang/String;)Lcom/google/android/mms/pdu/PduPart;
-Lcom/google/android/mms/pdu/PduBody;->getPartByContentLocation(Ljava/lang/String;)Lcom/google/android/mms/pdu/PduPart;
-Lcom/google/android/mms/pdu/PduBody;->getPartByFileName(Ljava/lang/String;)Lcom/google/android/mms/pdu/PduPart;
-Lcom/google/android/mms/pdu/PduBody;->getPartByName(Ljava/lang/String;)Lcom/google/android/mms/pdu/PduPart;
-Lcom/google/android/mms/pdu/PduBody;->getPartIndex(Lcom/google/android/mms/pdu/PduPart;)I
-Lcom/google/android/mms/pdu/PduBody;->getPartsNum()I
-Lcom/google/android/mms/pdu/PduBody;->removePart(I)Lcom/google/android/mms/pdu/PduPart;
-Lcom/google/android/mms/pdu/PduComposer$BufferStack;->copy()V
-Lcom/google/android/mms/pdu/PduComposer$BufferStack;->mark()Lcom/google/android/mms/pdu/PduComposer$PositionMarker;
-Lcom/google/android/mms/pdu/PduComposer$BufferStack;->newbuf()V
-Lcom/google/android/mms/pdu/PduComposer$BufferStack;->pop()V
-Lcom/google/android/mms/pdu/PduComposer$PositionMarker;->getLength()I
-Lcom/google/android/mms/pdu/PduComposer;-><init>(Landroid/content/Context;Lcom/google/android/mms/pdu/GenericPdu;)V
-Lcom/google/android/mms/pdu/PduComposer;->appendEncodedString(Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/PduComposer;->appendHeader(I)I
-Lcom/google/android/mms/pdu/PduComposer;->appendLongInteger(J)V
-Lcom/google/android/mms/pdu/PduComposer;->appendOctet(I)V
-Lcom/google/android/mms/pdu/PduComposer;->appendQuotedString(Ljava/lang/String;)V
-Lcom/google/android/mms/pdu/PduComposer;->appendQuotedString([B)V
-Lcom/google/android/mms/pdu/PduComposer;->appendShortInteger(I)V
-Lcom/google/android/mms/pdu/PduComposer;->appendTextString(Ljava/lang/String;)V
-Lcom/google/android/mms/pdu/PduComposer;->appendTextString([B)V
-Lcom/google/android/mms/pdu/PduComposer;->appendUintvarInteger(J)V
-Lcom/google/android/mms/pdu/PduComposer;->appendValueLength(J)V
-Lcom/google/android/mms/pdu/PduComposer;->arraycopy([BII)V
-Lcom/google/android/mms/pdu/PduComposer;->make()[B
-Lcom/google/android/mms/pdu/PduComposer;->mContentTypeMap:Ljava/util/HashMap;
-Lcom/google/android/mms/pdu/PduComposer;->mMessage:Ljava/io/ByteArrayOutputStream;
-Lcom/google/android/mms/pdu/PduComposer;->mPdu:Lcom/google/android/mms/pdu/GenericPdu;
-Lcom/google/android/mms/pdu/PduComposer;->mPduHeader:Lcom/google/android/mms/pdu/PduHeaders;
-Lcom/google/android/mms/pdu/PduComposer;->mPosition:I
-Lcom/google/android/mms/pdu/PduComposer;->mResolver:Landroid/content/ContentResolver;
-Lcom/google/android/mms/pdu/PduComposer;->mStack:Lcom/google/android/mms/pdu/PduComposer$BufferStack;
-Lcom/google/android/mms/pdu/PduContentTypes;->contentTypes:[Ljava/lang/String;
-Lcom/google/android/mms/pdu/PduHeaders;-><init>()V
-Lcom/google/android/mms/pdu/PduHeaders;->appendEncodedStringValue(Lcom/google/android/mms/pdu/EncodedStringValue;I)V
-Lcom/google/android/mms/pdu/PduHeaders;->getEncodedStringValue(I)Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/PduHeaders;->getEncodedStringValues(I)[Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/PduHeaders;->getLongInteger(I)J
-Lcom/google/android/mms/pdu/PduHeaders;->getOctet(I)I
-Lcom/google/android/mms/pdu/PduHeaders;->getTextString(I)[B
-Lcom/google/android/mms/pdu/PduHeaders;->setEncodedStringValue(Lcom/google/android/mms/pdu/EncodedStringValue;I)V
-Lcom/google/android/mms/pdu/PduHeaders;->setLongInteger(JI)V
-Lcom/google/android/mms/pdu/PduHeaders;->setOctet(II)V
Lcom/google/android/mms/pdu/PduParser;->$assertionsDisabled:Z
-Lcom/google/android/mms/pdu/PduParser;-><init>([BZ)V
-Lcom/google/android/mms/pdu/PduParser;->checkPartPosition(Lcom/google/android/mms/pdu/PduPart;)I
-Lcom/google/android/mms/pdu/PduParser;->log(Ljava/lang/String;)V
-Lcom/google/android/mms/pdu/PduParser;->parse()Lcom/google/android/mms/pdu/GenericPdu;
-Lcom/google/android/mms/pdu/PduParser;->parseContentType(Ljava/io/ByteArrayInputStream;Ljava/util/HashMap;)[B
-Lcom/google/android/mms/pdu/PduParser;->parsePartHeaders(Ljava/io/ByteArrayInputStream;Lcom/google/android/mms/pdu/PduPart;I)Z
-Lcom/google/android/mms/pdu/PduParser;->parseShortInteger(Ljava/io/ByteArrayInputStream;)I
-Lcom/google/android/mms/pdu/PduParser;->parseUnsignedInt(Ljava/io/ByteArrayInputStream;)I
-Lcom/google/android/mms/pdu/PduParser;->parseValueLength(Ljava/io/ByteArrayInputStream;)I
-Lcom/google/android/mms/pdu/PduParser;->parseWapString(Ljava/io/ByteArrayInputStream;I)[B
-Lcom/google/android/mms/pdu/PduPart;-><init>()V
-Lcom/google/android/mms/pdu/PduPart;->generateLocation()Ljava/lang/String;
-Lcom/google/android/mms/pdu/PduPart;->getCharset()I
-Lcom/google/android/mms/pdu/PduPart;->getContentDisposition()[B
-Lcom/google/android/mms/pdu/PduPart;->getContentId()[B
-Lcom/google/android/mms/pdu/PduPart;->getContentLocation()[B
-Lcom/google/android/mms/pdu/PduPart;->getContentTransferEncoding()[B
-Lcom/google/android/mms/pdu/PduPart;->getContentType()[B
-Lcom/google/android/mms/pdu/PduPart;->getData()[B
-Lcom/google/android/mms/pdu/PduPart;->getDataLength()I
-Lcom/google/android/mms/pdu/PduPart;->getDataUri()Landroid/net/Uri;
-Lcom/google/android/mms/pdu/PduPart;->getFilename()[B
-Lcom/google/android/mms/pdu/PduPart;->getName()[B
-Lcom/google/android/mms/pdu/PduPart;->setCharset(I)V
-Lcom/google/android/mms/pdu/PduPart;->setContentDisposition([B)V
-Lcom/google/android/mms/pdu/PduPart;->setContentId([B)V
-Lcom/google/android/mms/pdu/PduPart;->setContentLocation([B)V
-Lcom/google/android/mms/pdu/PduPart;->setContentTransferEncoding([B)V
-Lcom/google/android/mms/pdu/PduPart;->setContentType([B)V
-Lcom/google/android/mms/pdu/PduPart;->setData([B)V
-Lcom/google/android/mms/pdu/PduPart;->setDataUri(Landroid/net/Uri;)V
-Lcom/google/android/mms/pdu/PduPart;->setFilename([B)V
-Lcom/google/android/mms/pdu/PduPart;->setName([B)V
-Lcom/google/android/mms/pdu/PduPersister;->ADDRESS_FIELDS:[I
-Lcom/google/android/mms/pdu/PduPersister;->CHARSET_COLUMN_NAME_MAP:Ljava/util/HashMap;
-Lcom/google/android/mms/pdu/PduPersister;->ENCODED_STRING_COLUMN_NAME_MAP:Ljava/util/HashMap;
-Lcom/google/android/mms/pdu/PduPersister;->getByteArrayFromPartColumn(Landroid/database/Cursor;I)[B
-Lcom/google/android/mms/pdu/PduPersister;->getBytes(Ljava/lang/String;)[B
-Lcom/google/android/mms/pdu/PduPersister;->getIntegerFromPartColumn(Landroid/database/Cursor;I)Ljava/lang/Integer;
-Lcom/google/android/mms/pdu/PduPersister;->getPartContentType(Lcom/google/android/mms/pdu/PduPart;)Ljava/lang/String;
-Lcom/google/android/mms/pdu/PduPersister;->getPduPersister(Landroid/content/Context;)Lcom/google/android/mms/pdu/PduPersister;
-Lcom/google/android/mms/pdu/PduPersister;->getPendingMessages(J)Landroid/database/Cursor;
-Lcom/google/android/mms/pdu/PduPersister;->load(Landroid/net/Uri;)Lcom/google/android/mms/pdu/GenericPdu;
-Lcom/google/android/mms/pdu/PduPersister;->loadRecipients(ILjava/util/HashSet;Ljava/util/HashMap;Z)V
-Lcom/google/android/mms/pdu/PduPersister;->LONG_COLUMN_NAME_MAP:Ljava/util/HashMap;
-Lcom/google/android/mms/pdu/PduPersister;->mContentResolver:Landroid/content/ContentResolver;
-Lcom/google/android/mms/pdu/PduPersister;->mContext:Landroid/content/Context;
-Lcom/google/android/mms/pdu/PduPersister;->MESSAGE_BOX_MAP:Ljava/util/HashMap;
-Lcom/google/android/mms/pdu/PduPersister;->move(Landroid/net/Uri;Landroid/net/Uri;)Landroid/net/Uri;
-Lcom/google/android/mms/pdu/PduPersister;->mTelephonyManager:Landroid/telephony/TelephonyManager;
-Lcom/google/android/mms/pdu/PduPersister;->OCTET_COLUMN_NAME_MAP:Ljava/util/HashMap;
-Lcom/google/android/mms/pdu/PduPersister;->PART_PROJECTION:[Ljava/lang/String;
-Lcom/google/android/mms/pdu/PduPersister;->PDU_CACHE_INSTANCE:Lcom/google/android/mms/util/PduCache;
-Lcom/google/android/mms/pdu/PduPersister;->persist(Lcom/google/android/mms/pdu/GenericPdu;Landroid/net/Uri;ZZLjava/util/HashMap;)Landroid/net/Uri;
-Lcom/google/android/mms/pdu/PduPersister;->persistAddress(JI[Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/PduPersister;->persistPart(Lcom/google/android/mms/pdu/PduPart;JLjava/util/HashMap;)Landroid/net/Uri;
-Lcom/google/android/mms/pdu/PduPersister;->TEXT_STRING_COLUMN_NAME_MAP:Ljava/util/HashMap;
-Lcom/google/android/mms/pdu/PduPersister;->toIsoString([B)Ljava/lang/String;
-Lcom/google/android/mms/pdu/PduPersister;->updateAddress(JI[Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/PduPersister;->updateHeaders(Landroid/net/Uri;Lcom/google/android/mms/pdu/SendReq;)V
-Lcom/google/android/mms/pdu/PduPersister;->updateParts(Landroid/net/Uri;Lcom/google/android/mms/pdu/PduBody;Ljava/util/HashMap;)V
-Lcom/google/android/mms/pdu/QuotedPrintable;->decodeQuotedPrintable([B)[B
-Lcom/google/android/mms/pdu/ReadOrigInd;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V
-Lcom/google/android/mms/pdu/ReadOrigInd;->getMessageId()[B
-Lcom/google/android/mms/pdu/ReadOrigInd;->getReadStatus()I
-Lcom/google/android/mms/pdu/ReadRecInd;-><init>(Lcom/google/android/mms/pdu/EncodedStringValue;[BII[Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/ReadRecInd;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V
-Lcom/google/android/mms/pdu/ReadRecInd;->getMessageId()[B
-Lcom/google/android/mms/pdu/ReadRecInd;->setDate(J)V
-Lcom/google/android/mms/pdu/RetrieveConf;-><init>()V
-Lcom/google/android/mms/pdu/RetrieveConf;-><init>(Lcom/google/android/mms/pdu/PduHeaders;Lcom/google/android/mms/pdu/PduBody;)V
-Lcom/google/android/mms/pdu/RetrieveConf;->addCc(Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/RetrieveConf;->getCc()[Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/RetrieveConf;->getContentType()[B
-Lcom/google/android/mms/pdu/RetrieveConf;->getDeliveryReport()I
-Lcom/google/android/mms/pdu/RetrieveConf;->getFrom()Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/RetrieveConf;->getMessageClass()[B
-Lcom/google/android/mms/pdu/RetrieveConf;->getMessageId()[B
-Lcom/google/android/mms/pdu/RetrieveConf;->getReadReport()I
-Lcom/google/android/mms/pdu/RetrieveConf;->getRetrieveStatus()I
-Lcom/google/android/mms/pdu/RetrieveConf;->getRetrieveText()Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/RetrieveConf;->getTransactionId()[B
-Lcom/google/android/mms/pdu/RetrieveConf;->setContentType([B)V
-Lcom/google/android/mms/pdu/RetrieveConf;->setDeliveryReport(I)V
-Lcom/google/android/mms/pdu/RetrieveConf;->setFrom(Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/RetrieveConf;->setMessageClass([B)V
-Lcom/google/android/mms/pdu/RetrieveConf;->setMessageId([B)V
-Lcom/google/android/mms/pdu/RetrieveConf;->setReadReport(I)V
-Lcom/google/android/mms/pdu/RetrieveConf;->setRetrieveStatus(I)V
-Lcom/google/android/mms/pdu/RetrieveConf;->setRetrieveText(Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/RetrieveConf;->setTransactionId([B)V
-Lcom/google/android/mms/pdu/SendConf;-><init>()V
-Lcom/google/android/mms/pdu/SendConf;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V
-Lcom/google/android/mms/pdu/SendConf;->getMessageId()[B
-Lcom/google/android/mms/pdu/SendConf;->getResponseStatus()I
-Lcom/google/android/mms/pdu/SendConf;->getTransactionId()[B
-Lcom/google/android/mms/pdu/SendReq;-><init>()V
-Lcom/google/android/mms/pdu/SendReq;-><init>(Lcom/google/android/mms/pdu/PduHeaders;Lcom/google/android/mms/pdu/PduBody;)V
-Lcom/google/android/mms/pdu/SendReq;->addBcc(Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/SendReq;->addCc(Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/SendReq;->getBcc()[Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/SendReq;->getCc()[Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/SendReq;->getContentType()[B
-Lcom/google/android/mms/pdu/SendReq;->getDeliveryReport()I
-Lcom/google/android/mms/pdu/SendReq;->getExpiry()J
-Lcom/google/android/mms/pdu/SendReq;->getMessageClass()[B
-Lcom/google/android/mms/pdu/SendReq;->getMessageSize()J
-Lcom/google/android/mms/pdu/SendReq;->getReadReport()I
-Lcom/google/android/mms/pdu/SendReq;->getTransactionId()[B
-Lcom/google/android/mms/pdu/SendReq;->setBcc([Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/SendReq;->setCc([Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/SendReq;->setContentType([B)V
-Lcom/google/android/mms/pdu/SendReq;->setDeliveryReport(I)V
-Lcom/google/android/mms/pdu/SendReq;->setExpiry(J)V
-Lcom/google/android/mms/pdu/SendReq;->setMessageClass([B)V
-Lcom/google/android/mms/pdu/SendReq;->setMessageSize(J)V
-Lcom/google/android/mms/pdu/SendReq;->setReadReport(I)V
-Lcom/google/android/mms/pdu/SendReq;->setTo([Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/SendReq;->setTransactionId([B)V
-Lcom/google/android/mms/util/AbstractCache;-><init>()V
-Lcom/google/android/mms/util/AbstractCache;->get(Ljava/lang/Object;)Ljava/lang/Object;
-Lcom/google/android/mms/util/AbstractCache;->purge(Ljava/lang/Object;)Ljava/lang/Object;
-Lcom/google/android/mms/util/AbstractCache;->purgeAll()V
-Lcom/google/android/mms/util/AbstractCache;->put(Ljava/lang/Object;Ljava/lang/Object;)Z
-Lcom/google/android/mms/util/DownloadDrmHelper;->isDrmConvertNeeded(Ljava/lang/String;)Z
-Lcom/google/android/mms/util/DownloadDrmHelper;->modifyDrmFwLockFileExtension(Ljava/lang/String;)Ljava/lang/String;
-Lcom/google/android/mms/util/DrmConvertSession;->close(Ljava/lang/String;)I
-Lcom/google/android/mms/util/DrmConvertSession;->convert([BI)[B
-Lcom/google/android/mms/util/DrmConvertSession;->open(Landroid/content/Context;Ljava/lang/String;)Lcom/google/android/mms/util/DrmConvertSession;
-Lcom/google/android/mms/util/PduCache;-><init>()V
-Lcom/google/android/mms/util/PduCache;->getInstance()Lcom/google/android/mms/util/PduCache;
-Lcom/google/android/mms/util/PduCache;->isUpdating(Landroid/net/Uri;)Z
-Lcom/google/android/mms/util/PduCache;->purge(Landroid/net/Uri;)Lcom/google/android/mms/util/PduCacheEntry;
-Lcom/google/android/mms/util/PduCache;->purgeAll()V
-Lcom/google/android/mms/util/PduCacheEntry;-><init>(Lcom/google/android/mms/pdu/GenericPdu;IJ)V
-Lcom/google/android/mms/util/PduCacheEntry;->getMessageBox()I
-Lcom/google/android/mms/util/PduCacheEntry;->getPdu()Lcom/google/android/mms/pdu/GenericPdu;
-Lcom/google/android/mms/util/PduCacheEntry;->getThreadId()J
-Lcom/google/android/mms/util/SqliteWrapper;->checkSQLiteException(Landroid/content/Context;Landroid/database/sqlite/SQLiteException;)V
-Lcom/google/android/mms/util/SqliteWrapper;->delete(Landroid/content/Context;Landroid/content/ContentResolver;Landroid/net/Uri;Ljava/lang/String;[Ljava/lang/String;)I
-Lcom/google/android/mms/util/SqliteWrapper;->insert(Landroid/content/Context;Landroid/content/ContentResolver;Landroid/net/Uri;Landroid/content/ContentValues;)Landroid/net/Uri;
-Lcom/google/android/mms/util/SqliteWrapper;->query(Landroid/content/Context;Landroid/content/ContentResolver;Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)Landroid/database/Cursor;
-Lcom/google/android/mms/util/SqliteWrapper;->requery(Landroid/content/Context;Landroid/database/Cursor;)Z
-Lcom/google/android/mms/util/SqliteWrapper;->update(Landroid/content/Context;Landroid/content/ContentResolver;Landroid/net/Uri;Landroid/content/ContentValues;Ljava/lang/String;[Ljava/lang/String;)I
Lcom/google/android/util/AbstractMessageParser$Token$Type;->values()[Lcom/google/android/util/AbstractMessageParser$Token$Type;
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 553ef69..a6784780 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -191,6 +191,8 @@
import java.lang.ref.WeakReference;
import java.lang.reflect.Method;
import java.net.InetAddress;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Arrays;
@@ -6435,6 +6437,26 @@
NetworkSecurityConfigProvider.install(appContext);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+
+ if (isAppDebuggable) {
+ try {
+ // Load all the agents in the code_cache/startup_agents directory.
+ // We pass the absolute path to the data_dir as an argument.
+ Path startup_path = appContext.getCodeCacheDir().toPath().resolve("startup_agents");
+ if (Files.exists(startup_path)) {
+ for (Path p : Files.newDirectoryStream(startup_path)) {
+ handleAttachAgent(
+ p.toAbsolutePath().toString()
+ + "="
+ + appContext.getDataDir().toPath().toAbsolutePath().toString(),
+ data.info);
+ }
+ }
+ } catch (Exception e) {
+ // Ignored.
+ }
+ }
+
// Continue loading instrumentation.
if (ii != null) {
ApplicationInfo instrApp;
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 41733b3..9720e9f 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -50,6 +50,7 @@
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.MotionEvent;
+import android.view.SurfaceControl;
import android.view.ViewConfiguration;
import android.view.Window;
import android.view.WindowManagerGlobal;
@@ -528,6 +529,12 @@
} while (mWaitingActivities.contains(aw));
waitForEnterAnimationComplete(aw.activity);
+
+ // Apply an empty transaction to ensure SF has a chance to update before
+ // the Activity is ready (b/138263890).
+ try (SurfaceControl.Transaction t = new SurfaceControl.Transaction()) {
+ t.apply(true);
+ }
return aw.activity;
}
}
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index c58972e..635b9b0 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -112,7 +112,6 @@
import android.net.lowpan.LowpanManager;
import android.net.nsd.INsdManager;
import android.net.nsd.NsdManager;
-import android.net.wifi.IWifiManager;
import android.net.wifi.IWifiScanner;
import android.net.wifi.RttManager;
import android.net.wifi.WifiManager;
@@ -730,10 +729,8 @@
registerService(Context.WIFI_SERVICE, WifiManager.class,
new CachedServiceFetcher<WifiManager>() {
@Override
- public WifiManager createService(ContextImpl ctx) throws ServiceNotFoundException {
- IBinder b = ServiceManager.getServiceOrThrow(Context.WIFI_SERVICE);
- IWifiManager service = IWifiManager.Stub.asInterface(b);
- return new WifiManager(ctx.getOuterContext(), service,
+ public WifiManager createService(ContextImpl ctx) {
+ return new WifiManager(ctx.getOuterContext(),
ConnectivityThread.getInstanceLooper());
}});
@@ -1166,7 +1163,8 @@
@Override
public AppPredictionManager createService(ContextImpl ctx)
throws ServiceNotFoundException {
- return new AppPredictionManager(ctx);
+ IBinder b = ServiceManager.getService(Context.APP_PREDICTION_SERVICE);
+ return b == null ? null : new AppPredictionManager(ctx);
}
});
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 49cfd41..ff5a043 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -4991,26 +4991,60 @@
* call {@link android.security.KeyChain#choosePrivateKeyAlias} first.
*
* The grantee app will receive the {@link android.security.KeyChain#ACTION_KEY_ACCESS_CHANGED}
- * broadcast when access to a key is granted or revoked.
+ * broadcast when access to a key is granted.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
* {@code null} if calling from a delegated certificate installer.
* @param alias The alias of the key to grant access to.
* @param packageName The name of the (already installed) package to grant access to.
- * @param hasGrant Whether to grant access to the alias or revoke it.
* @return {@code true} if the grant was set successfully, {@code false} otherwise.
*
- * @throws SecurityException if the caller is not a device owner, a profile owner or
+ * @throws SecurityException if the caller is not a device owner, a profile owner or
* delegated certificate chooser.
* @throws IllegalArgumentException if {@code packageName} or {@code alias} are empty, or if
* {@code packageName} is not a name of an installed package.
+ * @see #revokeKeyPairFromApp
*/
- public boolean setKeyGrantForApp(@Nullable ComponentName admin, @NonNull String alias,
- @NonNull String packageName, boolean hasGrant) {
- throwIfParentInstance("addKeyGrant");
+ public boolean grantKeyPairToApp(@Nullable ComponentName admin, @NonNull String alias,
+ @NonNull String packageName) {
+ throwIfParentInstance("grantKeyPairToApp");
try {
return mService.setKeyGrantForApp(
- admin, mContext.getPackageName(), alias, packageName, hasGrant);
+ admin, mContext.getPackageName(), alias, packageName, true);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ return false;
+ }
+
+ /**
+ * Called by a device or profile owner, or delegated certificate chooser (an app that has been
+ * delegated the {@link #DELEGATION_CERT_SELECTION} privilege), to revoke an application's
+ * grant to a KeyChain key pair.
+ * Calls by the application to {@link android.security.KeyChain#getPrivateKey}
+ * will fail after the grant is revoked.
+ *
+ * The grantee app will receive the {@link android.security.KeyChain#ACTION_KEY_ACCESS_CHANGED}
+ * broadcast when access to a key is revoked.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
+ * {@code null} if calling from a delegated certificate installer.
+ * @param alias The alias of the key to revoke access from.
+ * @param packageName The name of the (already installed) package to revoke access from.
+ * @return {@code true} if the grant was revoked successfully, {@code false} otherwise.
+ *
+ * @throws SecurityException if the caller is not a device owner, a profile owner or
+ * delegated certificate chooser.
+ * @throws IllegalArgumentException if {@code packageName} or {@code alias} are empty, or if
+ * {@code packageName} is not a name of an installed package.
+ * @see #grantKeyPairToApp
+ */
+ public boolean revokeKeyPairFromApp(@Nullable ComponentName admin, @NonNull String alias,
+ @NonNull String packageName) {
+ throwIfParentInstance("revokeKeyPairFromApp");
+ try {
+ return mService.setKeyGrantForApp(
+ admin, mContext.getPackageName(), alias, packageName, false);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
diff --git a/core/java/android/companion/AssociationRequest.java b/core/java/android/companion/AssociationRequest.java
index e4114c6..ac40150 100644
--- a/core/java/android/companion/AssociationRequest.java
+++ b/core/java/android/companion/AssociationRequest.java
@@ -127,6 +127,12 @@
public Builder() {}
/**
+ * Whether only a single device should match the provided filter.
+ *
+ * When scanning for a single device with a specifc {@link BluetoothDeviceFilter} mac
+ * address, bonded devices are also searched among. This allows to obtain the necessary app
+ * privileges even if the device is already paired.
+ *
* @param singleDevice if true, scanning for a device will stop as soon as at least one
* fitting device is found
*/
diff --git a/services/core/java/com/android/server/compat/IPlatformCompat.aidl b/core/java/android/compat/IPlatformCompat.aidl
similarity index 90%
rename from services/core/java/com/android/server/compat/IPlatformCompat.aidl
rename to core/java/android/compat/IPlatformCompat.aidl
index 8ab08f9..3d8a9d5 100644
--- a/services/core/java/com/android/server/compat/IPlatformCompat.aidl
+++ b/core/java/android/compat/IPlatformCompat.aidl
@@ -14,12 +14,16 @@
* limitations under the License.
*/
-package com.android.server.compat;
+package android.compat;
import android.content.pm.ApplicationInfo;
/**
- * System private API for talking with the PlatformCompat service.
+ * Platform private API for talking with the PlatformCompat service.
+ *
+ * <p> Should be used for gating and logging from non-app processes.
+ * For app processes please use android.compat.Compatibility API.
+ *
* {@hide}
*/
interface IPlatformCompat
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 4ea3726..65c11d7 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -17,6 +17,7 @@
package android.content;
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.MODE_DEFAULT;
import static android.app.AppOpsManager.MODE_ERRORED;
@@ -645,9 +646,11 @@
}
boolean checkUser(int pid, int uid, Context context) {
- return UserHandle.getUserId(uid) == context.getUserId()
- || mSingleUser
- || context.checkPermission(INTERACT_ACROSS_USERS, pid, uid)
+ if (UserHandle.getUserId(uid) == context.getUserId() || mSingleUser) {
+ return true;
+ }
+ return context.checkPermission(INTERACT_ACROSS_USERS, pid, uid) == PERMISSION_GRANTED
+ || context.checkPermission(INTERACT_ACROSS_USERS_FULL, pid, uid)
== PERMISSION_GRANTED;
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 73bc908..2c53faa 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -38,6 +38,7 @@
import android.app.IApplicationThread;
import android.app.IServiceConnection;
import android.app.VrManager;
+import android.compat.IPlatformCompat;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
@@ -3228,6 +3229,7 @@
ROLE_SERVICE,
//@hide ROLE_CONTROLLER_SERVICE,
CAMERA_SERVICE,
+ //@hide: PLATFORM_COMPAT_SERVICE,
PRINT_SERVICE,
CONSUMER_IR_SERVICE,
//@hide: TRUST_SERVICE,
@@ -3735,6 +3737,14 @@
public static final String NETWORK_STACK_SERVICE = "network_stack";
/**
+ * Use with {@link android.os.ServiceManager.getService()} to retrieve a
+ * {@link android.net.WifiStackClient} IBinder for communicating with the network stack
+ * @hide
+ * @see android.net.WifiStackClient
+ */
+ public static final String WIFI_STACK_SERVICE = "wifi_stack";
+
+ /**
* Use with {@link #getSystemService(String)} to retrieve a
* {@link android.net.IpSecManager} for encrypting Sockets or Networks with
* IPSec.
@@ -4109,6 +4119,9 @@
/**
* Official published name of the app prediction service.
*
+ * <p><b>NOTE: </b> this service is optional; callers of
+ * {@code Context.getSystemServiceName(APP_PREDICTION_SERVICE)} should check for {@code null}.
+ *
* @hide
* @see #getSystemService(String)
*/
@@ -4586,6 +4599,13 @@
public static final String STATS_MANAGER = "stats";
/**
+ * Use with {@link android.os.ServiceManager.getService()} to retrieve a
+ * {@link IPlatformCompat} IBinder for communicating with the platform compat service.
+ * @hide
+ */
+ public static final String PLATFORM_COMPAT_SERVICE = "platform_compat";
+
+ /**
* Service to capture a bugreport.
* @see #getSystemService(String)
* @see android.os.BugreportManager
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 895eba6..c561013 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -38,6 +38,8 @@
import android.app.PackageInstallObserver;
import android.app.admin.DevicePolicyManager;
import android.app.usage.StorageStatsManager;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -3369,6 +3371,17 @@
*/
public static final int VERSION_CODE_HIGHEST = -1;
+ /**
+ * Apps targeting Android R and above will need to declare the packages and intents they intend
+ * to use to get details about other apps on a device. Such declarations must be made via the
+ * {@code <queries>} tag in the manifest.
+ *
+ * @hide
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
+ public static final long FILTER_APPLICATION_QUERY = 135549675L;
+
/** {@hide} */
public int getUserId() {
return UserHandle.myUserId();
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 2f198ac..f50502e 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -675,12 +675,6 @@
"android.content.pm.extra.ENABLE_ROLLBACK_INSTALL_FLAGS";
/**
- * Extra field name for the set of installed users for a given rollback package.
- */
- public static final String EXTRA_ENABLE_ROLLBACK_INSTALLED_USERS =
- "android.content.pm.extra.ENABLE_ROLLBACK_INSTALLED_USERS";
-
- /**
* Extra field name for the user id an install is associated with when
* enabling rollback.
*/
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index 1c37c64..fcdc81c 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -16,11 +16,17 @@
package android.content.pm;
+import android.annotation.IntDef;
import android.annotation.UnsupportedAppUsage;
+import android.annotation.UserIdInt;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.UserHandle;
import android.os.UserManager;
+import android.util.DebugUtils;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
/**
* Per-user information.
@@ -119,10 +125,31 @@
*/
public static final int FLAG_SYSTEM = 0x00000800;
+ /**
+ * @hide
+ */
+ @IntDef(flag = true, prefix = "FLAG_", value = {
+ FLAG_PRIMARY,
+ FLAG_ADMIN,
+ FLAG_GUEST,
+ FLAG_RESTRICTED,
+ FLAG_INITIALIZED,
+ FLAG_MANAGED_PROFILE,
+ FLAG_DISABLED,
+ FLAG_QUIET_MODE,
+ FLAG_EPHEMERAL,
+ FLAG_DEMO,
+ FLAG_FULL,
+ FLAG_SYSTEM
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface UserInfoFlag {
+ }
+
public static final int NO_PROFILE_GROUP_ID = UserHandle.USER_NULL;
@UnsupportedAppUsage
- public int id;
+ public @UserIdInt int id;
@UnsupportedAppUsage
public int serialNumber;
@UnsupportedAppUsage
@@ -130,7 +157,7 @@
@UnsupportedAppUsage
public String iconPath;
@UnsupportedAppUsage
- public int flags;
+ public @UserInfoFlag int flags;
@UnsupportedAppUsage
public long creationTime;
@UnsupportedAppUsage
@@ -214,6 +241,10 @@
return (flags & FLAG_DEMO) == FLAG_DEMO;
}
+ public boolean isFull() {
+ return (flags & FLAG_FULL) == FLAG_FULL;
+ }
+
/**
* Returns true if the user is a split system user.
* <p>If {@link UserManager#isSplitSystemUser split system user mode} is not enabled,
@@ -290,13 +321,23 @@
@Override
public String toString() {
+ // NOTE: do not change this string, it's used by 'pm list users', which in turn is
+ // used and parsed by TestDevice. In other words, if you change it, you'd have to change
+ // TestDevice, TestDeviceTest, and possibly others....
return "UserInfo{" + id + ":" + name + ":" + Integer.toHexString(flags) + "}";
}
+ /** @hide */
+ public static String flagsToString(int flags) {
+ return DebugUtils.flagsToString(UserInfo.class, "FLAG_", flags);
+ }
+
+ @Override
public int describeContents() {
return 0;
}
+ @Override
public void writeToParcel(Parcel dest, int parcelableFlags) {
dest.writeInt(id);
dest.writeString(name);
diff --git a/core/java/android/content/rollback/PackageRollbackInfo.java b/core/java/android/content/rollback/PackageRollbackInfo.java
index 2014751..c89796d 100644
--- a/core/java/android/content/rollback/PackageRollbackInfo.java
+++ b/core/java/android/content/rollback/PackageRollbackInfo.java
@@ -76,10 +76,10 @@
private final boolean mIsApex;
/*
- * The list of users the package is installed for.
+ * The list of users for which snapshots have been saved.
*/
// NOTE: Not a part of the Parcelable representation of this object.
- private final IntArray mInstalledUsers;
+ private final IntArray mSnapshottedUsers;
/**
* A mapping between user and an inode of theirs CE data snapshot.
@@ -148,8 +148,8 @@
}
/** @hide */
- public IntArray getInstalledUsers() {
- return mInstalledUsers;
+ public IntArray getSnapshottedUsers() {
+ return mSnapshottedUsers;
}
/** @hide */
@@ -179,14 +179,14 @@
public PackageRollbackInfo(VersionedPackage packageRolledBackFrom,
VersionedPackage packageRolledBackTo,
@NonNull IntArray pendingBackups, @NonNull ArrayList<RestoreInfo> pendingRestores,
- boolean isApex, @NonNull IntArray installedUsers,
+ boolean isApex, @NonNull IntArray snapshottedUsers,
@NonNull SparseLongArray ceSnapshotInodes) {
this.mVersionRolledBackFrom = packageRolledBackFrom;
this.mVersionRolledBackTo = packageRolledBackTo;
this.mPendingBackups = pendingBackups;
this.mPendingRestores = pendingRestores;
this.mIsApex = isApex;
- this.mInstalledUsers = installedUsers;
+ this.mSnapshottedUsers = snapshottedUsers;
this.mCeSnapshotInodes = ceSnapshotInodes;
}
@@ -196,7 +196,7 @@
this.mIsApex = in.readBoolean();
this.mPendingRestores = null;
this.mPendingBackups = null;
- this.mInstalledUsers = null;
+ this.mSnapshottedUsers = null;
this.mCeSnapshotInodes = null;
}
diff --git a/core/java/android/content/rollback/RollbackManager.java b/core/java/android/content/rollback/RollbackManager.java
index 73b8a48..1609f53 100644
--- a/core/java/android/content/rollback/RollbackManager.java
+++ b/core/java/android/content/rollback/RollbackManager.java
@@ -74,7 +74,10 @@
}
/**
- * Returns a list of all currently available rollbacks.
+ * Returns a list of all currently available rollbacks. This includes ones for very recently
+ * installed packages (even if onFinished has not yet been called). As a result, packages that
+ * very recently failed to install may also be included, but those rollbacks will fail with
+ * 'rollback not available'.
*
* @throws SecurityException if the caller does not have appropriate permissions.
*/
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index 099ae29..e78fb7f 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -339,6 +339,8 @@
* for {@link #TYPE_STEP_COUNTER} instead. It is defined as a
* {@link Sensor#REPORTING_MODE_SPECIAL_TRIGGER} sensor.
* <p>
+ * This sensor requires permission {@code android.permission.ACTIVITY_RECOGNITION}.
+ * <p>
* See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details.
*/
public static final int TYPE_STEP_DETECTOR = 18;
@@ -384,8 +386,6 @@
* gyroscope. This sensor uses lower power than the other rotation vectors, because it doesn't
* use the gyroscope. However, it is more noisy and will work best outdoors.
* <p>
- * This sensor requires permission {@code android.permission.ACTIVITY_RECOGNITION}.
- * <p>
* See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details.
*/
public static final int TYPE_GEOMAGNETIC_ROTATION_VECTOR = 20;
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index 1142a07..fb6b231 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -100,9 +100,12 @@
/**
* @hide
*/
- public static final int DISMISSED_REASON_POSITIVE = 1;
+ public static final int DISMISSED_REASON_CONFIRMED = 1;
/**
+ * Dialog is done animating away after user clicked on the button set via
+ * {@link BiometricPrompt.Builder#setNegativeButton(CharSequence, Executor,
+ * DialogInterface.OnClickListener)}.
* @hide
*/
public static final int DISMISSED_REASON_NEGATIVE = 2;
@@ -112,6 +115,25 @@
*/
public static final int DISMISSED_REASON_USER_CANCEL = 3;
+ /**
+ * Authenticated, confirmation not required. Dialog animated away.
+ * @hide
+ */
+ public static final int DISMISSED_REASON_CONFIRM_NOT_REQUIRED = 4;
+
+ /**
+ * Error message shown on SystemUI. When BiometricService receives this, the UI is already
+ * gone.
+ * @hide
+ */
+ public static final int DISMISSED_REASON_ERROR = 5;
+
+ /**
+ * Dialog dismissal requested by BiometricService.
+ * @hide
+ */
+ public static final int DISMISSED_REASON_SERVER_REQUESTED = 6;
+
private static class ButtonInfo {
Executor executor;
DialogInterface.OnClickListener listener;
@@ -362,7 +384,7 @@
@Override
public void onDialogDismissed(int reason) throws RemoteException {
// Check the reason and invoke OnClickListener(s) if necessary
- if (reason == DISMISSED_REASON_POSITIVE) {
+ if (reason == DISMISSED_REASON_CONFIRMED) {
mPositiveButtonInfo.executor.execute(() -> {
mPositiveButtonInfo.listener.onClick(null, DialogInterface.BUTTON_POSITIVE);
});
diff --git a/core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl b/core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl
index 180daaf..ca6114e 100644
--- a/core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl
@@ -27,8 +27,8 @@
// Notify BiometricService that authentication was successful. If user confirmation is required,
// the auth token must be submitted into KeyStore.
void onAuthenticationSucceeded(boolean requireConfirmation, in byte[] token);
- // Notify BiometricService that an error has occurred.
- void onAuthenticationFailed(int cookie, boolean requireConfirmation);
+ // Notify BiometricService authentication was rejected.
+ void onAuthenticationFailed();
// Notify BiometricService than an error has occured. Forward to the correct receiver depending
// on the cookie.
void onError(int cookie, int error, String message);
diff --git a/core/java/android/hardware/radio/TunerCallbackAdapter.java b/core/java/android/hardware/radio/TunerCallbackAdapter.java
index 0fb93e5..beff0f7 100644
--- a/core/java/android/hardware/radio/TunerCallbackAdapter.java
+++ b/core/java/android/hardware/radio/TunerCallbackAdapter.java
@@ -211,10 +211,12 @@
@Override
public void onProgramListUpdated(ProgramList.Chunk chunk) {
- synchronized (mLock) {
- if (mProgramList == null) return;
- mProgramList.apply(Objects.requireNonNull(chunk));
- }
+ mHandler.post(() -> {
+ synchronized (mLock) {
+ if (mProgramList == null) return;
+ mProgramList.apply(Objects.requireNonNull(chunk));
+ }
+ });
}
@Override
diff --git a/core/java/android/inputmethodservice/SoftInputWindow.java b/core/java/android/inputmethodservice/SoftInputWindow.java
index 0513fee..356b344 100644
--- a/core/java/android/inputmethodservice/SoftInputWindow.java
+++ b/core/java/android/inputmethodservice/SoftInputWindow.java
@@ -21,6 +21,7 @@
import android.annotation.IntDef;
import android.app.Dialog;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.graphics.Rect;
import android.os.Debug;
import android.os.IBinder;
@@ -50,6 +51,7 @@
final int mWindowType;
final int mGravity;
final boolean mTakesFocus;
+ final boolean mAutomotiveHideNavBarForKeyboard;
private final Rect mBounds = new Rect();
@Retention(SOURCE)
@@ -134,6 +136,8 @@
mWindowType = windowType;
mGravity = gravity;
mTakesFocus = takesFocus;
+ mAutomotiveHideNavBarForKeyboard = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_automotiveHideNavBarForKeyboard);
initDockWindow();
}
@@ -247,6 +251,11 @@
windowModFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
}
+ if (isAutomotive() && mAutomotiveHideNavBarForKeyboard) {
+ windowSetFlags |= WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
+ windowModFlags |= WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
+ }
+
getWindow().setFlags(windowSetFlags, windowModFlags);
}
@@ -338,6 +347,10 @@
mWindowState = newState;
}
+ private boolean isAutomotive() {
+ return getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
+ }
+
private static String stateToString(@SoftInputWindowState int state) {
switch (state) {
case SoftInputWindowState.TOKEN_PENDING:
diff --git a/core/java/android/net/util/MultinetworkPolicyTracker.java b/core/java/android/net/util/MultinetworkPolicyTracker.java
index 30c5cd9..f7e494d 100644
--- a/core/java/android/net/util/MultinetworkPolicyTracker.java
+++ b/core/java/android/net/util/MultinetworkPolicyTracker.java
@@ -16,29 +16,32 @@
package android.net.util;
+import static android.provider.Settings.Global.NETWORK_AVOID_BAD_WIFI;
+import static android.provider.Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE;
+
+import android.annotation.NonNull;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.res.Resources;
import android.database.ContentObserver;
-import android.net.ConnectivityManager;
import android.net.Uri;
import android.os.Handler;
-import android.os.Message;
import android.os.UserHandle;
import android.provider.Settings;
+import android.telephony.PhoneStateListener;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
import android.util.Slog;
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.util.Arrays;
import java.util.List;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.R;
-
-import static android.provider.Settings.Global.NETWORK_AVOID_BAD_WIFI;
-import static android.provider.Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE;
-
/**
* A class to encapsulate management of the "Smart Networking" capability of
* avoiding bad Wi-Fi when, for example upstream connectivity is lost or
@@ -69,6 +72,7 @@
private volatile boolean mAvoidBadWifi = true;
private volatile int mMeteredMultipathPreference;
+ private int mActiveSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
public MultinetworkPolicyTracker(Context ctx, Handler handler) {
this(ctx, handler, null);
@@ -95,6 +99,14 @@
}
};
+ TelephonyManager.from(ctx).listen(new PhoneStateListener() {
+ @Override
+ public void onActiveDataSubscriptionIdChanged(int subId) {
+ mActiveSubId = subId;
+ reevaluate();
+ }
+ }, PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE);
+
updateAvoidBadWifi();
updateMeteredMultipathPreference();
}
@@ -131,7 +143,12 @@
* Whether the device or carrier configuration disables avoiding bad wifi by default.
*/
public boolean configRestrictsAvoidBadWifi() {
- return (mContext.getResources().getInteger(R.integer.config_networkAvoidBadWifi) == 0);
+ return (getResourcesForActiveSubId().getInteger(R.integer.config_networkAvoidBadWifi) == 0);
+ }
+
+ @NonNull
+ private Resources getResourcesForActiveSubId() {
+ return SubscriptionManager.getResourcesForSubId(mContext, mActiveSubId);
}
/**
diff --git a/core/java/android/os/UserManagerInternal.java b/core/java/android/os/UserManagerInternal.java
index 2e3b000..f302263 100644
--- a/core/java/android/os/UserManagerInternal.java
+++ b/core/java/android/os/UserManagerInternal.java
@@ -16,6 +16,7 @@
package android.os;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.content.Context;
import android.content.pm.UserInfo;
import android.graphics.Bitmap;
@@ -224,4 +225,10 @@
/** @return a specific user restriction that's in effect currently. */
public abstract boolean hasUserRestriction(String restriction, int userId);
+
+ /**
+ * Gets an {@link UserInfo} for the given {@code userId}, or {@code null} if not
+ * found.
+ */
+ public abstract @Nullable UserInfo getUserInfo(@UserIdInt int userId);
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index d414ab1..e486235 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -16,16 +16,19 @@
package android.provider;
-import static android.provider.SettingsValidators.ANY_INTEGER_VALIDATOR;
-import static android.provider.SettingsValidators.ANY_STRING_VALIDATOR;
-import static android.provider.SettingsValidators.BOOLEAN_VALIDATOR;
-import static android.provider.SettingsValidators.COMPONENT_NAME_VALIDATOR;
-import static android.provider.SettingsValidators.LENIENT_IP_ADDRESS_VALIDATOR;
-import static android.provider.SettingsValidators.LOCALE_VALIDATOR;
-import static android.provider.SettingsValidators.NON_NEGATIVE_INTEGER_VALIDATOR;
-import static android.provider.SettingsValidators.NULLABLE_COMPONENT_NAME_VALIDATOR;
-import static android.provider.SettingsValidators.PACKAGE_NAME_VALIDATOR;
-import static android.provider.SettingsValidators.URI_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.ANY_INTEGER_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.ANY_STRING_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.BOOLEAN_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.COMPONENT_NAME_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.JSON_OBJECT_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.LENIENT_IP_ADDRESS_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.LOCALE_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.NON_NEGATIVE_INTEGER_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.NULLABLE_COMPONENT_NAME_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.PACKAGE_NAME_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.TILE_LIST_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.TTS_LIST_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.URI_VALIDATOR;
import android.Manifest;
import android.annotation.IntDef;
@@ -80,7 +83,12 @@
import android.os.ResultReceiver;
import android.os.ServiceManager;
import android.os.UserHandle;
-import android.provider.SettingsValidators.Validator;
+import android.provider.settings.validators.ComponentNameListValidator;
+import android.provider.settings.validators.DiscreteValueValidator;
+import android.provider.settings.validators.InclusiveFloatRangeValidator;
+import android.provider.settings.validators.InclusiveIntegerRangeValidator;
+import android.provider.settings.validators.PackageNameListValidator;
+import android.provider.settings.validators.Validator;
import android.speech.tts.TextToSpeech;
import android.telephony.SubscriptionManager;
import android.text.TextUtils;
@@ -3149,7 +3157,7 @@
public static final String END_BUTTON_BEHAVIOR = "end_button_behavior";
private static final Validator END_BUTTON_BEHAVIOR_VALIDATOR =
- new SettingsValidators.InclusiveIntegerRangeValidator(0, 3);
+ new InclusiveIntegerRangeValidator(0, 3);
/**
* END_BUTTON_BEHAVIOR value for "go home".
@@ -3351,7 +3359,7 @@
"bluetooth_discoverability";
private static final Validator BLUETOOTH_DISCOVERABILITY_VALIDATOR =
- new SettingsValidators.InclusiveIntegerRangeValidator(0, 2);
+ new InclusiveIntegerRangeValidator(0, 2);
/**
* Bluetooth discoverability timeout. If this value is nonzero, then
@@ -3495,7 +3503,7 @@
public static final String PEAK_REFRESH_RATE = "peak_refresh_rate";
private static final Validator PEAK_REFRESH_RATE_VALIDATOR =
- new SettingsValidators.InclusiveFloatRangeValidator(24f, Float.MAX_VALUE);
+ new InclusiveFloatRangeValidator(24f, Float.MAX_VALUE);
/**
* The amount of time in milliseconds before the device goes to sleep or begins
@@ -3524,7 +3532,7 @@
public static final String SCREEN_BRIGHTNESS_FOR_VR = "screen_brightness_for_vr";
private static final Validator SCREEN_BRIGHTNESS_FOR_VR_VALIDATOR =
- new SettingsValidators.InclusiveIntegerRangeValidator(0, 255);
+ new InclusiveIntegerRangeValidator(0, 255);
/**
* Control whether to enable automatic brightness mode.
@@ -3542,7 +3550,7 @@
public static final String SCREEN_AUTO_BRIGHTNESS_ADJ = "screen_auto_brightness_adj";
private static final Validator SCREEN_AUTO_BRIGHTNESS_ADJ_VALIDATOR =
- new SettingsValidators.InclusiveFloatRangeValidator(-1, 1);
+ new InclusiveFloatRangeValidator(-1, 1);
/**
* SCREEN_BRIGHTNESS_MODE value for manual mode.
@@ -3676,7 +3684,7 @@
"haptic_feedback_intensity";
private static final Validator VIBRATION_INTENSITY_VALIDATOR =
- new SettingsValidators.InclusiveIntegerRangeValidator(0, 3);
+ new InclusiveIntegerRangeValidator(0, 3);
/**
* Ringer volume. This is used internally, changing this value will not
@@ -3766,7 +3774,7 @@
public static final String MASTER_BALANCE = "master_balance";
private static final Validator MASTER_BALANCE_VALIDATOR =
- new SettingsValidators.InclusiveFloatRangeValidator(-1.f, 1.f);
+ new InclusiveFloatRangeValidator(-1.f, 1.f);
/**
* Whether the notifications should use the ring volume (value of 1) or
@@ -4004,7 +4012,7 @@
/** @hide */
public static final Validator TIME_12_24_VALIDATOR =
- new SettingsValidators.DiscreteValueValidator(new String[] {"12", "24", null});
+ new DiscreteValueValidator(new String[] {"12", "24", null});
/**
* Date format string
@@ -4090,7 +4098,7 @@
/** @hide */
public static final Validator USER_ROTATION_VALIDATOR =
- new SettingsValidators.InclusiveIntegerRangeValidator(0, 3);
+ new InclusiveIntegerRangeValidator(0, 3);
/**
* Control whether the rotation lock toggle in the System UI should be hidden.
@@ -4179,7 +4187,7 @@
/** @hide */
public static final Validator TTY_MODE_VALIDATOR =
- new SettingsValidators.InclusiveIntegerRangeValidator(0, 3);
+ new InclusiveIntegerRangeValidator(0, 3);
/**
* Whether the sounds effects (key clicks, lid open ...) are enabled. The value is
@@ -4381,7 +4389,7 @@
/** @hide */
public static final Validator SIP_CALL_OPTIONS_VALIDATOR =
- new SettingsValidators.DiscreteValueValidator(
+ new DiscreteValueValidator(
new String[] {"SIP_ALWAYS", "SIP_ADDRESS_ONLY"});
/**
@@ -4428,7 +4436,7 @@
/** @hide */
public static final Validator POINTER_SPEED_VALIDATOR =
- new SettingsValidators.InclusiveFloatRangeValidator(-7, 7);
+ new InclusiveFloatRangeValidator(-7, 7);
/**
* Whether lock-to-app will be triggered by long-press on recents.
@@ -6352,7 +6360,7 @@
public static final String LOCK_SCREEN_CUSTOM_CLOCK_FACE = "lock_screen_custom_clock_face";
private static final Validator LOCK_SCREEN_CUSTOM_CLOCK_FACE_VALIDATOR =
- SettingsValidators.JSON_OBJECT_VALIDATOR;
+ JSON_OBJECT_VALIDATOR;
/**
* Indicates which clock face to show on lock screen and AOD while docked.
@@ -6509,7 +6517,7 @@
"enabled_accessibility_services";
private static final Validator ENABLED_ACCESSIBILITY_SERVICES_VALIDATOR =
- new SettingsValidators.ComponentNameListValidator(":");
+ new ComponentNameListValidator(":");
/**
* List of the accessibility services to which the user has granted
@@ -6521,7 +6529,7 @@
"touch_exploration_granted_accessibility_services";
private static final Validator TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES_VALIDATOR =
- new SettingsValidators.ComponentNameListValidator(":");
+ new ComponentNameListValidator(":");
/**
* Whether the Global Actions Panel is enabled.
@@ -6696,7 +6704,7 @@
"accessibility_display_magnification_scale";
private static final Validator ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE_VALIDATOR =
- new SettingsValidators.InclusiveFloatRangeValidator(1.0f, Float.MAX_VALUE);
+ new InclusiveFloatRangeValidator(1.0f, Float.MAX_VALUE);
/**
* Unused mangnification setting
@@ -6780,7 +6788,7 @@
"accessibility_captioning_preset";
private static final Validator ACCESSIBILITY_CAPTIONING_PRESET_VALIDATOR =
- new SettingsValidators.DiscreteValueValidator(new String[]{"-1", "0", "1", "2",
+ new DiscreteValueValidator(new String[]{"-1", "0", "1", "2",
"3", "4"});
/**
@@ -6824,7 +6832,7 @@
"accessibility_captioning_edge_type";
private static final Validator ACCESSIBILITY_CAPTIONING_EDGE_TYPE_VALIDATOR =
- new SettingsValidators.DiscreteValueValidator(new String[]{"0", "1", "2"});
+ new DiscreteValueValidator(new String[]{"0", "1", "2"});
/**
* Integer property that specifes the edge color for captions as a
@@ -6870,7 +6878,7 @@
"accessibility_captioning_typeface";
private static final Validator ACCESSIBILITY_CAPTIONING_TYPEFACE_VALIDATOR =
- new SettingsValidators.DiscreteValueValidator(new String[]{"DEFAULT",
+ new DiscreteValueValidator(new String[]{"DEFAULT",
"MONOSPACE", "SANS_SERIF", "SERIF"});
/**
@@ -6882,7 +6890,7 @@
"accessibility_captioning_font_scale";
private static final Validator ACCESSIBILITY_CAPTIONING_FONT_SCALE_VALIDATOR =
- new SettingsValidators.InclusiveFloatRangeValidator(0.5f, 2.0f);
+ new InclusiveFloatRangeValidator(0.5f, 2.0f);
/**
* Setting that specifies whether display color inversion is enabled.
@@ -6923,7 +6931,7 @@
"accessibility_display_daltonizer";
private static final Validator ACCESSIBILITY_DISPLAY_DALTONIZER_VALIDATOR =
- new SettingsValidators.DiscreteValueValidator(
+ new DiscreteValueValidator(
new String[] {"-1", "0", "11", "12", "13"});
/**
@@ -7112,8 +7120,7 @@
*/
public static final String TTS_DEFAULT_LOCALE = "tts_default_locale";
- private static final Validator TTS_DEFAULT_LOCALE_VALIDATOR =
- new SettingsValidators.TTSListValidator();
+ private static final Validator TTS_DEFAULT_LOCALE_VALIDATOR = TTS_LIST_VALIDATOR;
/**
* Space delimited list of plugin packages that are enabled.
@@ -7121,7 +7128,7 @@
public static final String TTS_ENABLED_PLUGINS = "tts_enabled_plugins";
private static final Validator TTS_ENABLED_PLUGINS_VALIDATOR =
- new SettingsValidators.PackageNameListValidator(" ");
+ new PackageNameListValidator(" ");
/**
* @deprecated Use {@link android.provider.Settings.Global#WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON}
@@ -7315,7 +7322,7 @@
"preferred_tty_mode";
private static final Validator PREFERRED_TTY_MODE_VALIDATOR =
- new SettingsValidators.DiscreteValueValidator(new String[]{"0", "1", "2", "3"});
+ new DiscreteValueValidator(new String[]{"0", "1", "2", "3"});
/**
* Whether the enhanced voice privacy mode is enabled.
@@ -7630,7 +7637,7 @@
public static final String INCALL_POWER_BUTTON_BEHAVIOR = "incall_power_button_behavior";
private static final Validator INCALL_POWER_BUTTON_BEHAVIOR_VALIDATOR =
- new SettingsValidators.DiscreteValueValidator(new String[]{"1", "2"});
+ new DiscreteValueValidator(new String[]{"1", "2"});
/**
* INCALL_POWER_BUTTON_BEHAVIOR value for "turn off screen".
@@ -7851,7 +7858,7 @@
public static final String UI_NIGHT_MODE = "ui_night_mode";
private static final Validator UI_NIGHT_MODE_VALIDATOR =
- new SettingsValidators.InclusiveIntegerRangeValidator(0, 2);
+ new InclusiveIntegerRangeValidator(0, 2);
/**
* Whether screensavers are enabled.
@@ -7871,7 +7878,7 @@
public static final String SCREENSAVER_COMPONENTS = "screensaver_components";
private static final Validator SCREENSAVER_COMPONENTS_VALIDATOR =
- new SettingsValidators.ComponentNameListValidator(",");
+ new ComponentNameListValidator(",");
/**
* If screensavers are enabled, whether the screensaver should be automatically launched
@@ -8023,7 +8030,7 @@
"enabled_notification_assistant";
private static final Validator ENABLED_NOTIFICATION_ASSISTANT_VALIDATOR =
- new SettingsValidators.ComponentNameListValidator(":");
+ new ComponentNameListValidator(":");
/**
* Read only list of the service components that the current user has explicitly allowed to
@@ -8038,7 +8045,7 @@
public static final String ENABLED_NOTIFICATION_LISTENERS = "enabled_notification_listeners";
private static final Validator ENABLED_NOTIFICATION_LISTENERS_VALIDATOR =
- new SettingsValidators.ComponentNameListValidator(":");
+ new ComponentNameListValidator(":");
/**
* Read only list of the packages that the current user has explicitly allowed to
@@ -8053,7 +8060,7 @@
"enabled_notification_policy_access_packages";
private static final Validator ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES_VALIDATOR =
- new SettingsValidators.PackageNameListValidator(":");
+ new PackageNameListValidator(":");
/**
* Defines whether managed profile ringtones should be synced from it's parent profile
@@ -8350,16 +8357,6 @@
BOOLEAN_VALIDATOR;
/**
- * Whether or not the face unlock education screen has been shown to the user.
- * @hide
- */
- public static final String FACE_UNLOCK_EDUCATION_INFO_DISPLAYED =
- "face_unlock_education_info_displayed";
-
- private static final Validator FACE_UNLOCK_EDUCATION_INFO_DISPLAYED_VALIDATOR =
- BOOLEAN_VALIDATOR;
-
- /**
* Whether or not debugging is enabled.
* @hide
*/
@@ -8446,7 +8443,7 @@
public static final String NIGHT_DISPLAY_AUTO_MODE = "night_display_auto_mode";
private static final Validator NIGHT_DISPLAY_AUTO_MODE_VALIDATOR =
- new SettingsValidators.InclusiveIntegerRangeValidator(0, 2);
+ new InclusiveIntegerRangeValidator(0, 2);
/**
* Control the color temperature of Night Display, represented in Kelvin.
@@ -8507,7 +8504,7 @@
public static final String ENABLED_VR_LISTENERS = "enabled_vr_listeners";
private static final Validator ENABLED_VR_LISTENERS_VALIDATOR =
- new SettingsValidators.ComponentNameListValidator(":");
+ new ComponentNameListValidator(":");
/**
* Behavior of the display while in VR mode.
@@ -8519,7 +8516,7 @@
public static final String VR_DISPLAY_MODE = "vr_display_mode";
private static final Validator VR_DISPLAY_MODE_VALIDATOR =
- new SettingsValidators.DiscreteValueValidator(new String[]{"0", "1"});
+ new DiscreteValueValidator(new String[]{"0", "1"});
/**
* Lower the display persistence while the system is in VR mode.
@@ -8638,8 +8635,7 @@
*/
public static final String QS_TILES = "sysui_qs_tiles";
- private static final Validator QS_TILES_VALIDATOR =
- new SettingsValidators.TileListValidator();
+ private static final Validator QS_TILES_VALIDATOR = TILE_LIST_VALIDATOR;
/**
* Specifies whether the web action API is enabled.
@@ -8705,8 +8701,7 @@
*/
public static final String QS_AUTO_ADDED_TILES = "qs_auto_tiles";
- private static final Validator QS_AUTO_ADDED_TILES_VALIDATOR =
- new SettingsValidators.TileListValidator();
+ private static final Validator QS_AUTO_ADDED_TILES_VALIDATOR = TILE_LIST_VALIDATOR;
/**
* Whether the Lockdown button should be shown in the power menu.
@@ -8867,7 +8862,7 @@
"theme_customization_overlay_packages";
private static final Validator THEME_CUSTOMIZATION_OVERLAY_PACKAGES_VALIDATOR =
- SettingsValidators.JSON_OBJECT_VALIDATOR;
+ JSON_OBJECT_VALIDATOR;
/**
* Navigation bar mode.
@@ -8879,7 +8874,7 @@
public static final String NAVIGATION_MODE =
"navigation_mode";
private static final Validator NAVIGATION_MODE_VALIDATOR =
- new SettingsValidators.DiscreteValueValidator(new String[] {"0", "1", "2"});
+ new DiscreteValueValidator(new String[] {"0", "1", "2"});
/**
* Controls whether aware is enabled.
@@ -9182,8 +9177,6 @@
VALIDATORS.put(FACE_UNLOCK_APP_ENABLED, FACE_UNLOCK_APP_ENABLED_VALIDATOR);
VALIDATORS.put(FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION,
FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION_VALIDATOR);
- VALIDATORS.put(FACE_UNLOCK_EDUCATION_INFO_DISPLAYED,
- FACE_UNLOCK_EDUCATION_INFO_DISPLAYED_VALIDATOR);
VALIDATORS.put(ASSIST_GESTURE_ENABLED, ASSIST_GESTURE_ENABLED_VALIDATOR);
VALIDATORS.put(ASSIST_GESTURE_SILENCE_ALERTS_ENABLED,
ASSIST_GESTURE_SILENCE_ALERTS_ENABLED_VALIDATOR);
@@ -10717,7 +10710,7 @@
"network_recommendations_enabled";
private static final Validator NETWORK_RECOMMENDATIONS_ENABLED_VALIDATOR =
- new SettingsValidators.DiscreteValueValidator(new String[] {"-1", "0", "1"});
+ new DiscreteValueValidator(new String[] {"-1", "0", "1"});
/**
* Which package name to use for network recommendations. If null, network recommendations
@@ -11042,12 +11035,6 @@
public static final String WIFI_P2P_DEVICE_NAME = "wifi_p2p_device_name";
/**
- * The min time between wifi disable and wifi enable
- * @hide
- */
- public static final String WIFI_REENABLE_DELAY_MS = "wifi_reenable_delay";
-
- /**
* Timeout for ephemeral networks when all known BSSIDs go out of range. We will disconnect
* from an ephemeral network if there is no BSSID for that network with a non-null score that
* has been seen in this time period.
@@ -12574,7 +12561,7 @@
public static final String EMERGENCY_TONE = "emergency_tone";
private static final Validator EMERGENCY_TONE_VALIDATOR =
- new SettingsValidators.DiscreteValueValidator(new String[] {"0", "1", "2"});
+ new DiscreteValueValidator(new String[] {"0", "1", "2"});
/**
* CDMA only settings
@@ -12604,7 +12591,7 @@
"enable_automatic_system_server_heap_dumps";
private static final Validator ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS_VALIDATOR =
- new SettingsValidators.DiscreteValueValidator(new String[] {"0", "1"});
+ new DiscreteValueValidator(new String[] {"0", "1"});
/**
* See RIL_PreferredNetworkType in ril.h
@@ -12798,7 +12785,7 @@
"low_power_sticky_auto_disable_level";
private static final Validator LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL_VALIDATOR =
- new SettingsValidators.InclusiveIntegerRangeValidator(0, 100);
+ new InclusiveIntegerRangeValidator(0, 100);
/**
* Whether sticky battery saver should be deactivated once the battery level has reached the
@@ -12810,7 +12797,7 @@
"low_power_sticky_auto_disable_enabled";
private static final Validator LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED_VALIDATOR =
- new SettingsValidators.DiscreteValueValidator(new String[] {"0", "1"});
+ new DiscreteValueValidator(new String[] {"0", "1"});
/**
* Battery level [1-100] at which low power mode automatically turns on.
@@ -12825,7 +12812,7 @@
public static final String LOW_POWER_MODE_TRIGGER_LEVEL = "low_power_trigger_level";
private static final Validator LOW_POWER_MODE_TRIGGER_LEVEL_VALIDATOR =
- new SettingsValidators.InclusiveIntegerRangeValidator(0, 100);
+ new InclusiveIntegerRangeValidator(0, 100);
/**
* Whether battery saver is currently set to trigger based on percentage, dynamic power
@@ -12838,7 +12825,7 @@
public static final String AUTOMATIC_POWER_SAVE_MODE = "automatic_power_save_mode";
private static final Validator AUTOMATIC_POWER_SAVE_MODE_VALIDATOR =
- new SettingsValidators.DiscreteValueValidator(new String[] {"0", "1"});
+ new DiscreteValueValidator(new String[] {"0", "1"});
/**
* The setting that backs the disable threshold for the setPowerSavingsWarning api in
@@ -12851,7 +12838,7 @@
public static final String DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD =
"dynamic_power_savings_disable_threshold";
private static final Validator DYNAMIC_POWER_SAVINGS_VALIDATOR =
- new SettingsValidators.InclusiveIntegerRangeValidator(0, 100);
+ new InclusiveIntegerRangeValidator(0, 100);
/**
* The setting which backs the setDynamicPowerSaveHint api in PowerManager.
@@ -13001,7 +12988,7 @@
public static final String ENCODED_SURROUND_OUTPUT = "encoded_surround_output";
private static final Validator ENCODED_SURROUND_OUTPUT_VALIDATOR =
- new SettingsValidators.DiscreteValueValidator(new String[] {"0", "1", "2", "3"});
+ new DiscreteValueValidator(new String[] {"0", "1", "2", "3"});
/**
* Surround sounds formats that are enabled when ENCODED_SURROUND_OUTPUT is set to
@@ -13752,7 +13739,7 @@
public static final String POWER_BUTTON_LONG_PRESS =
"power_button_long_press";
private static final Validator POWER_BUTTON_LONG_PRESS_VALIDATOR =
- new SettingsValidators.InclusiveIntegerRangeValidator(0, 5);
+ new InclusiveIntegerRangeValidator(0, 5);
/**
* Overrides internal R.integer.config_veryLongPressOnPowerBehavior.
@@ -13763,7 +13750,7 @@
public static final String POWER_BUTTON_VERY_LONG_PRESS =
"power_button_very_long_press";
private static final Validator POWER_BUTTON_VERY_LONG_PRESS_VALIDATOR =
- new SettingsValidators.InclusiveIntegerRangeValidator(0, 1);
+ new InclusiveIntegerRangeValidator(0, 1);
/**
* Settings to backup. This is here so that it's in the same place as the settings
diff --git a/core/java/android/provider/SettingsValidators.java b/core/java/android/provider/SettingsValidators.java
deleted file mode 100644
index e4cf9fd..0000000
--- a/core/java/android/provider/SettingsValidators.java
+++ /dev/null
@@ -1,332 +0,0 @@
-/*
- * Copyright (C) 2018 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.provider;
-
-import android.annotation.Nullable;
-import android.content.ComponentName;
-import android.net.Uri;
-import android.text.TextUtils;
-
-import com.android.internal.util.ArrayUtils;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.util.Locale;
-
-/**
- * This class provides both interface for validation and common validators
- * used to ensure Settings have meaningful values.
- *
- * @hide
- */
-public class SettingsValidators {
-
- public static final Validator BOOLEAN_VALIDATOR =
- new DiscreteValueValidator(new String[] {"0", "1"});
-
- public static final Validator ANY_STRING_VALIDATOR = new Validator() {
- @Override
- public boolean validate(@Nullable String value) {
- return true;
- }
- };
-
- public static final Validator NON_NEGATIVE_INTEGER_VALIDATOR = new Validator() {
- @Override
- public boolean validate(@Nullable String value) {
- try {
- return Integer.parseInt(value) >= 0;
- } catch (NumberFormatException e) {
- return false;
- }
- }
- };
-
- public static final Validator ANY_INTEGER_VALIDATOR = new Validator() {
- @Override
- public boolean validate(@Nullable String value) {
- try {
- Integer.parseInt(value);
- return true;
- } catch (NumberFormatException e) {
- return false;
- }
- }
- };
-
- public static final Validator URI_VALIDATOR = new Validator() {
- @Override
- public boolean validate(@Nullable String value) {
- try {
- Uri.decode(value);
- return true;
- } catch (IllegalArgumentException e) {
- return false;
- }
- }
- };
-
- /**
- * Does not allow a setting to have a null {@link ComponentName}. Use {@link
- * SettingsValidators#NULLABLE_COMPONENT_NAME_VALIDATOR} instead if a setting can have a
- * nullable {@link ComponentName}.
- */
- public static final Validator COMPONENT_NAME_VALIDATOR = new Validator() {
- @Override
- public boolean validate(@Nullable String value) {
- return value != null && ComponentName.unflattenFromString(value) != null;
- }
- };
-
- /**
- * Allows a setting to have a null {@link ComponentName}.
- */
- public static final Validator NULLABLE_COMPONENT_NAME_VALIDATOR = new Validator() {
- @Override
- public boolean validate(@Nullable String value) {
- return value == null || COMPONENT_NAME_VALIDATOR.validate(value);
- }
- };
-
- public static final Validator PACKAGE_NAME_VALIDATOR = new Validator() {
- @Override
- public boolean validate(@Nullable String value) {
- return value != null && isStringPackageName(value);
- }
-
- private boolean isStringPackageName(String value) {
- // The name may contain uppercase or lowercase letters ('A' through 'Z'), numbers,
- // and underscores ('_'). However, individual package name parts may only
- // start with letters.
- // (https://developer.android.com/guide/topics/manifest/manifest-element.html#package)
- if (value == null) {
- return false;
- }
- String[] subparts = value.split("\\.");
- boolean isValidPackageName = true;
- for (String subpart : subparts) {
- isValidPackageName &= isSubpartValidForPackageName(subpart);
- if (!isValidPackageName) break;
- }
- return isValidPackageName;
- }
-
- private boolean isSubpartValidForPackageName(String subpart) {
- if (subpart.length() == 0) return false;
- boolean isValidSubpart = Character.isLetter(subpart.charAt(0));
- for (int i = 1; i < subpart.length(); i++) {
- isValidSubpart &= (Character.isLetterOrDigit(subpart.charAt(i))
- || (subpart.charAt(i) == '_'));
- if (!isValidSubpart) break;
- }
- return isValidSubpart;
- }
- };
-
- public static final Validator LENIENT_IP_ADDRESS_VALIDATOR = new Validator() {
- private static final int MAX_IPV6_LENGTH = 45;
-
- @Override
- public boolean validate(@Nullable String value) {
- if (value == null) {
- return false;
- }
- return value.length() <= MAX_IPV6_LENGTH;
- }
- };
-
- public static final Validator LOCALE_VALIDATOR = new Validator() {
- @Override
- public boolean validate(@Nullable String value) {
- if (value == null) {
- return false;
- }
- Locale[] validLocales = Locale.getAvailableLocales();
- for (Locale locale : validLocales) {
- if (value.equals(locale.toString())) {
- return true;
- }
- }
- return false;
- }
- };
-
- /** {@link Validator} that checks whether a value is a valid {@link JSONObject}. */
- public static final Validator JSON_OBJECT_VALIDATOR = (value) -> {
- if (TextUtils.isEmpty(value)) {
- return false;
- }
- try {
- new JSONObject(value);
- return true;
- } catch (JSONException e) {
- return false;
- }
- };
-
- public interface Validator {
- /**
- * Returns whether the input value is valid. Subclasses should handle the case where the
- * input value is {@code null}.
- */
- boolean validate(@Nullable String value);
- }
-
- public static final class DiscreteValueValidator implements Validator {
- private final String[] mValues;
-
- public DiscreteValueValidator(String[] values) {
- mValues = values;
- }
-
- @Override
- public boolean validate(@Nullable String value) {
- return ArrayUtils.contains(mValues, value);
- }
- }
-
- public static final class InclusiveIntegerRangeValidator implements Validator {
- private final int mMin;
- private final int mMax;
-
- public InclusiveIntegerRangeValidator(int min, int max) {
- mMin = min;
- mMax = max;
- }
-
- @Override
- public boolean validate(@Nullable String value) {
- try {
- final int intValue = Integer.parseInt(value);
- return intValue >= mMin && intValue <= mMax;
- } catch (NumberFormatException e) {
- return false;
- }
- }
- }
-
- public static final class InclusiveFloatRangeValidator implements Validator {
- private final float mMin;
- private final float mMax;
-
- public InclusiveFloatRangeValidator(float min, float max) {
- mMin = min;
- mMax = max;
- }
-
- @Override
- public boolean validate(@Nullable String value) {
- try {
- final float floatValue = Float.parseFloat(value);
- return floatValue >= mMin && floatValue <= mMax;
- } catch (NumberFormatException | NullPointerException e) {
- return false;
- }
- }
- }
-
- public static final class ComponentNameListValidator implements Validator {
- private final String mSeparator;
-
- public ComponentNameListValidator(String separator) {
- mSeparator = separator;
- }
-
- @Override
- public boolean validate(@Nullable String value) {
- if (value == null) {
- return false;
- }
- String[] elements = value.split(mSeparator);
- for (String element : elements) {
- if (!COMPONENT_NAME_VALIDATOR.validate(element)) {
- return false;
- }
- }
- return true;
- }
- }
-
- public static final class PackageNameListValidator implements Validator {
- private final String mSeparator;
-
- public PackageNameListValidator(String separator) {
- mSeparator = separator;
- }
-
- @Override
- public boolean validate(@Nullable String value) {
- if (value == null) {
- return false;
- }
- String[] elements = value.split(mSeparator);
- for (String element : elements) {
- if (!PACKAGE_NAME_VALIDATOR.validate(element)) {
- return false;
- }
- }
- return true;
- }
- }
-
- private abstract static class ListValidator implements Validator {
- public boolean validate(@Nullable String value) {
- if (!isEntryValid(value)) {
- return false;
- }
- String[] items = value.split(",");
- for (String item : items) {
- if (!isItemValid(item)) {
- return false;
- }
- }
- return true;
- }
-
- protected abstract boolean isEntryValid(String entry);
-
- protected abstract boolean isItemValid(String item);
- }
-
- /** Ensure a restored value is a string in the format the text-to-speech system handles */
- public static final class TTSListValidator extends ListValidator {
- protected boolean isEntryValid(String entry) {
- return entry != null && entry.length() > 0;
- }
-
- protected boolean isItemValid(String item) {
- String[] parts = item.split(":");
- // Replaces any old language separator (-) with the new one (_)
- return ((parts.length == 2)
- && (parts[0].length() > 0)
- && ANY_STRING_VALIDATOR.validate(parts[0])
- && LOCALE_VALIDATOR.validate(parts[1].replace('-', '_')));
- }
- }
-
- /** Ensure a restored value is suitable to be used as a tile name */
- public static final class TileListValidator extends ListValidator {
- protected boolean isEntryValid(String entry) {
- return entry != null;
- }
-
- protected boolean isItemValid(String item) {
- return item.length() > 0 && ANY_STRING_VALIDATOR.validate(item);
- }
- }
-}
diff --git a/core/java/android/provider/TEST_MAPPING b/core/java/android/provider/TEST_MAPPING
new file mode 100644
index 0000000..52a6a45
--- /dev/null
+++ b/core/java/android/provider/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsProviderTestCases",
+ "options": [
+ {
+ "include-annotation": "android.platform.test.annotations.Presubmit"
+ }
+ ]
+ }
+ ]
+}
diff --git a/core/java/android/provider/settings/validators/ComponentNameListValidator.java b/core/java/android/provider/settings/validators/ComponentNameListValidator.java
new file mode 100644
index 0000000..b6b867a
--- /dev/null
+++ b/core/java/android/provider/settings/validators/ComponentNameListValidator.java
@@ -0,0 +1,40 @@
+/*
+ * 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.provider.settings.validators;
+
+import static android.provider.settings.validators.SettingsValidators.COMPONENT_NAME_VALIDATOR;
+
+/**
+ * Validate a list of compoments.
+ *
+ * @hide
+ */
+public final class ComponentNameListValidator extends ListValidator {
+ public ComponentNameListValidator(String separator) {
+ super(separator);
+ }
+
+ @Override
+ protected boolean isEntryValid(String entry) {
+ return entry != null;
+ }
+
+ @Override
+ protected boolean isItemValid(String item) {
+ return COMPONENT_NAME_VALIDATOR.validate(item);
+ }
+}
diff --git a/core/java/android/provider/settings/validators/DiscreteValueValidator.java b/core/java/android/provider/settings/validators/DiscreteValueValidator.java
new file mode 100644
index 0000000..183651f
--- /dev/null
+++ b/core/java/android/provider/settings/validators/DiscreteValueValidator.java
@@ -0,0 +1,39 @@
+/*
+ * 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.provider.settings.validators;
+
+import android.annotation.Nullable;
+
+import com.android.internal.util.ArrayUtils;
+
+/**
+ * Validate a value exists in an array of known good values
+ *
+ * @hide
+ */
+public final class DiscreteValueValidator implements Validator {
+ private final String[] mValues;
+
+ public DiscreteValueValidator(String[] values) {
+ mValues = values;
+ }
+
+ @Override
+ public boolean validate(@Nullable String value) {
+ return ArrayUtils.contains(mValues, value);
+ }
+}
diff --git a/core/java/android/provider/settings/validators/InclusiveFloatRangeValidator.java b/core/java/android/provider/settings/validators/InclusiveFloatRangeValidator.java
new file mode 100644
index 0000000..38400ac
--- /dev/null
+++ b/core/java/android/provider/settings/validators/InclusiveFloatRangeValidator.java
@@ -0,0 +1,44 @@
+/*
+ * 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.provider.settings.validators;
+
+import android.annotation.Nullable;
+
+/**
+ * Validate a float value lies within a given (boundary inclusive) range.
+ *
+ * @hide
+ */
+public final class InclusiveFloatRangeValidator implements Validator {
+ private final float mMin;
+ private final float mMax;
+
+ public InclusiveFloatRangeValidator(float min, float max) {
+ mMin = min;
+ mMax = max;
+ }
+
+ @Override
+ public boolean validate(@Nullable String value) {
+ try {
+ final float floatValue = Float.parseFloat(value);
+ return floatValue >= mMin && floatValue <= mMax;
+ } catch (NumberFormatException | NullPointerException e) {
+ return false;
+ }
+ }
+}
diff --git a/core/java/android/provider/settings/validators/InclusiveIntegerRangeValidator.java b/core/java/android/provider/settings/validators/InclusiveIntegerRangeValidator.java
new file mode 100644
index 0000000..e53c252
--- /dev/null
+++ b/core/java/android/provider/settings/validators/InclusiveIntegerRangeValidator.java
@@ -0,0 +1,44 @@
+/*
+ * 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.provider.settings.validators;
+
+import android.annotation.Nullable;
+
+/**
+ * Validate an integer value lies within a given (boundary inclusive) range.
+ *
+ * @hide
+ */
+public final class InclusiveIntegerRangeValidator implements Validator {
+ private final int mMin;
+ private final int mMax;
+
+ public InclusiveIntegerRangeValidator(int min, int max) {
+ mMin = min;
+ mMax = max;
+ }
+
+ @Override
+ public boolean validate(@Nullable String value) {
+ try {
+ final int intValue = Integer.parseInt(value);
+ return intValue >= mMin && intValue <= mMax;
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }
+}
diff --git a/core/java/android/provider/settings/validators/ListValidator.java b/core/java/android/provider/settings/validators/ListValidator.java
new file mode 100644
index 0000000..a6001d2
--- /dev/null
+++ b/core/java/android/provider/settings/validators/ListValidator.java
@@ -0,0 +1,51 @@
+/*
+ * 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.provider.settings.validators;
+
+import android.annotation.Nullable;
+
+/**
+ * Validate the elements in a list.
+ *
+ * @hide
+ */
+abstract class ListValidator implements Validator {
+
+ private String mListSplitRegex;
+
+ ListValidator(String listSplitRegex) {
+ mListSplitRegex = listSplitRegex;
+ }
+
+ public boolean validate(@Nullable String value) {
+ if (!isEntryValid(value)) {
+ return false;
+ }
+ String[] items = value.split(",");
+ for (String item : items) {
+ if (!isItemValid(item)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ protected abstract boolean isEntryValid(String entry);
+
+ protected abstract boolean isItemValid(String item);
+}
+
diff --git a/core/java/android/provider/settings/validators/PackageNameListValidator.java b/core/java/android/provider/settings/validators/PackageNameListValidator.java
new file mode 100644
index 0000000..bc7fc13
--- /dev/null
+++ b/core/java/android/provider/settings/validators/PackageNameListValidator.java
@@ -0,0 +1,40 @@
+/*
+ * 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.provider.settings.validators;
+
+import static android.provider.settings.validators.SettingsValidators.PACKAGE_NAME_VALIDATOR;
+
+/**
+ * Validate a list of package names.
+ *
+ * @hide
+ */
+public final class PackageNameListValidator extends ListValidator {
+ public PackageNameListValidator(String separator) {
+ super(separator);
+ }
+
+ @Override
+ protected boolean isEntryValid(String entry) {
+ return entry != null;
+ }
+
+ @Override
+ protected boolean isItemValid(String item) {
+ return PACKAGE_NAME_VALIDATOR.validate(item);
+ }
+}
diff --git a/core/java/android/provider/settings/validators/SettingsValidators.java b/core/java/android/provider/settings/validators/SettingsValidators.java
new file mode 100644
index 0000000..562c638
--- /dev/null
+++ b/core/java/android/provider/settings/validators/SettingsValidators.java
@@ -0,0 +1,183 @@
+/*
+ * 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.provider.settings.validators;
+
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.net.Uri;
+import android.text.TextUtils;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.Locale;
+
+/**
+ * This class provides both interface for validation and common validators
+ * used to ensure Settings have meaningful values.
+ *
+ * @hide
+ */
+public class SettingsValidators {
+
+ public static final Validator BOOLEAN_VALIDATOR =
+ new DiscreteValueValidator(new String[] {"0", "1"});
+
+ public static final Validator ANY_STRING_VALIDATOR = new Validator() {
+ @Override
+ public boolean validate(@Nullable String value) {
+ return true;
+ }
+ };
+
+ public static final Validator NON_NEGATIVE_INTEGER_VALIDATOR = new Validator() {
+ @Override
+ public boolean validate(@Nullable String value) {
+ try {
+ return Integer.parseInt(value) >= 0;
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }
+ };
+
+ public static final Validator ANY_INTEGER_VALIDATOR = new Validator() {
+ @Override
+ public boolean validate(@Nullable String value) {
+ try {
+ Integer.parseInt(value);
+ return true;
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }
+ };
+
+ public static final Validator URI_VALIDATOR = new Validator() {
+ @Override
+ public boolean validate(@Nullable String value) {
+ try {
+ Uri.decode(value);
+ return true;
+ } catch (IllegalArgumentException e) {
+ return false;
+ }
+ }
+ };
+
+ /**
+ * Does not allow a setting to have a null {@link ComponentName}. Use {@link
+ * SettingsValidators#NULLABLE_COMPONENT_NAME_VALIDATOR} instead if a setting can have a
+ * nullable {@link ComponentName}.
+ */
+ public static final Validator COMPONENT_NAME_VALIDATOR = new Validator() {
+ @Override
+ public boolean validate(@Nullable String value) {
+ return value != null && ComponentName.unflattenFromString(value) != null;
+ }
+ };
+
+ /**
+ * Allows a setting to have a null {@link ComponentName}.
+ */
+ public static final Validator NULLABLE_COMPONENT_NAME_VALIDATOR = new Validator() {
+ @Override
+ public boolean validate(@Nullable String value) {
+ return value == null || COMPONENT_NAME_VALIDATOR.validate(value);
+ }
+ };
+
+ public static final Validator PACKAGE_NAME_VALIDATOR = new Validator() {
+ @Override
+ public boolean validate(@Nullable String value) {
+ return value != null && isStringPackageName(value);
+ }
+
+ private boolean isStringPackageName(String value) {
+ // The name may contain uppercase or lowercase letters ('A' through 'Z'), numbers,
+ // and underscores ('_'). However, individual package name parts may only
+ // start with letters.
+ // (https://developer.android.com/guide/topics/manifest/manifest-element.html#package)
+ if (value == null) {
+ return false;
+ }
+ String[] subparts = value.split("\\.");
+ boolean isValidPackageName = true;
+ for (String subpart : subparts) {
+ isValidPackageName &= isSubpartValidForPackageName(subpart);
+ if (!isValidPackageName) break;
+ }
+ return isValidPackageName;
+ }
+
+ private boolean isSubpartValidForPackageName(String subpart) {
+ if (subpart.length() == 0) return false;
+ boolean isValidSubpart = Character.isLetter(subpart.charAt(0));
+ for (int i = 1; i < subpart.length(); i++) {
+ isValidSubpart &= (Character.isLetterOrDigit(subpart.charAt(i))
+ || (subpart.charAt(i) == '_'));
+ if (!isValidSubpart) break;
+ }
+ return isValidSubpart;
+ }
+ };
+
+ public static final Validator LENIENT_IP_ADDRESS_VALIDATOR = new Validator() {
+ private static final int MAX_IPV6_LENGTH = 45;
+
+ @Override
+ public boolean validate(@Nullable String value) {
+ if (value == null) {
+ return false;
+ }
+ return value.length() <= MAX_IPV6_LENGTH;
+ }
+ };
+
+ public static final Validator LOCALE_VALIDATOR = new Validator() {
+ @Override
+ public boolean validate(@Nullable String value) {
+ if (value == null) {
+ return false;
+ }
+ Locale[] validLocales = Locale.getAvailableLocales();
+ for (Locale locale : validLocales) {
+ if (value.equals(locale.toString())) {
+ return true;
+ }
+ }
+ return false;
+ }
+ };
+
+ /** {@link Validator} that checks whether a value is a valid {@link JSONObject}. */
+ public static final Validator JSON_OBJECT_VALIDATOR = (value) -> {
+ if (TextUtils.isEmpty(value)) {
+ return false;
+ }
+ try {
+ new JSONObject(value);
+ return true;
+ } catch (JSONException e) {
+ return false;
+ }
+ };
+
+ public static final Validator TTS_LIST_VALIDATOR = new TTSListValidator();
+
+ public static final Validator TILE_LIST_VALIDATOR = new TileListValidator();
+}
diff --git a/core/java/android/provider/settings/validators/TTSListValidator.java b/core/java/android/provider/settings/validators/TTSListValidator.java
new file mode 100644
index 0000000..6c73471
--- /dev/null
+++ b/core/java/android/provider/settings/validators/TTSListValidator.java
@@ -0,0 +1,45 @@
+/*
+ * 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.provider.settings.validators;
+
+import static android.provider.settings.validators.SettingsValidators.ANY_STRING_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.LOCALE_VALIDATOR;
+
+/**
+ * Ensure a restored value is a string in the format the text-to-speech system handles
+ *
+ * @hide
+ */
+final class TTSListValidator extends ListValidator {
+
+ TTSListValidator() {
+ super(",");
+ }
+
+ protected boolean isEntryValid(String entry) {
+ return entry != null && entry.length() > 0;
+ }
+
+ protected boolean isItemValid(String item) {
+ String[] parts = item.split(":");
+ // Replaces any old language separator (-) with the new one (_)
+ return ((parts.length == 2)
+ && (parts[0].length() > 0)
+ && ANY_STRING_VALIDATOR.validate(parts[0])
+ && LOCALE_VALIDATOR.validate(parts[1].replace('-', '_')));
+ }
+}
diff --git a/core/java/android/provider/settings/validators/TileListValidator.java b/core/java/android/provider/settings/validators/TileListValidator.java
new file mode 100644
index 0000000..c696442
--- /dev/null
+++ b/core/java/android/provider/settings/validators/TileListValidator.java
@@ -0,0 +1,38 @@
+/*
+ * 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.provider.settings.validators;
+
+import static android.provider.settings.validators.SettingsValidators.ANY_STRING_VALIDATOR;
+
+/**
+ * Ensure a restored value is suitable to be used as a tile name
+ *
+ * @hide
+ */
+final class TileListValidator extends ListValidator {
+ TileListValidator() {
+ super(",");
+ }
+
+ protected boolean isEntryValid(String entry) {
+ return entry != null;
+ }
+
+ protected boolean isItemValid(String item) {
+ return item.length() > 0 && ANY_STRING_VALIDATOR.validate(item);
+ }
+}
diff --git a/core/java/android/provider/settings/validators/Validator.java b/core/java/android/provider/settings/validators/Validator.java
new file mode 100644
index 0000000..393a03d
--- /dev/null
+++ b/core/java/android/provider/settings/validators/Validator.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 android.provider.settings.validators;
+
+import android.annotation.Nullable;
+
+/**
+ * Interface for a settings value validator.
+ *
+ * @hide
+ */
+public interface Validator {
+ /**
+ * Returns whether the input value is valid. Subclasses should handle the case where the
+ * input value is {@code null}.
+ */
+ boolean validate(@Nullable String value);
+}
diff --git a/core/java/android/service/gatekeeper/GateKeeperResponse.java b/core/java/android/service/gatekeeper/GateKeeperResponse.java
index 66fee1e..7ed733c 100644
--- a/core/java/android/service/gatekeeper/GateKeeperResponse.java
+++ b/core/java/android/service/gatekeeper/GateKeeperResponse.java
@@ -31,6 +31,8 @@
public static final int RESPONSE_OK = 0;
public static final int RESPONSE_RETRY = 1;
+ public static final GateKeeperResponse ERROR = createGenericResponse(RESPONSE_ERROR);
+
private final int mResponseCode;
private int mTimeout;
diff --git a/core/java/android/util/Half.java b/core/java/android/util/Half.java
index 70d049a..fe536a6 100644
--- a/core/java/android/util/Half.java
+++ b/core/java/android/util/Half.java
@@ -20,6 +20,8 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import libcore.util.FP16;
+
/**
* <p>The {@code Half} class is a wrapper and a utility class to manipulate half-precision 16-bit
* <a href="https://en.wikipedia.org/wiki/Half-precision_floating-point_format">IEEE 754</a>
@@ -148,25 +150,6 @@
*/
public static final @HalfFloat short POSITIVE_ZERO = (short) 0x0000;
- private static final int FP16_SIGN_SHIFT = 15;
- private static final int FP16_SIGN_MASK = 0x8000;
- private static final int FP16_EXPONENT_SHIFT = 10;
- private static final int FP16_EXPONENT_MASK = 0x1f;
- private static final int FP16_SIGNIFICAND_MASK = 0x3ff;
- private static final int FP16_EXPONENT_BIAS = 15;
- private static final int FP16_COMBINED = 0x7fff;
- private static final int FP16_EXPONENT_MAX = 0x7c00;
-
- private static final int FP32_SIGN_SHIFT = 31;
- private static final int FP32_EXPONENT_SHIFT = 23;
- private static final int FP32_EXPONENT_MASK = 0xff;
- private static final int FP32_SIGNIFICAND_MASK = 0x7fffff;
- private static final int FP32_EXPONENT_BIAS = 127;
- private static final int FP32_QNAN_MASK = 0x400000;
-
- private static final int FP32_DENORMAL_MAGIC = 126 << 23;
- private static final float FP32_DENORMAL_FLOAT = Float.intBitsToFloat(FP32_DENORMAL_MAGIC);
-
private final @HalfFloat short mValue;
/**
@@ -414,16 +397,7 @@
* than {@code y}
*/
public static int compare(@HalfFloat short x, @HalfFloat short y) {
- if (less(x, y)) return -1;
- if (greater(x, y)) return 1;
-
- // Collapse NaNs, akin to halfToIntBits(), but we want to keep
- // (signed) short value types to preserve the ordering of -0.0
- // and +0.0
- short xBits = (x & FP16_COMBINED) > FP16_EXPONENT_MAX ? NaN : x;
- short yBits = (y & FP16_COMBINED) > FP16_EXPONENT_MAX ? NaN : y;
-
- return (xBits == yBits ? 0 : (xBits < yBits ? -1 : 1));
+ return FP16.compare(x, y);
}
/**
@@ -440,7 +414,7 @@
* @see #halfToIntBits(short)
*/
public static @HalfFloat short halfToShortBits(@HalfFloat short h) {
- return (h & FP16_COMBINED) > FP16_EXPONENT_MAX ? NaN : h;
+ return (h & FP16.EXPONENT_SIGNIFICAND_MASK) > FP16.POSITIVE_INFINITY ? NaN : h;
}
/**
@@ -459,7 +433,7 @@
* @see #intBitsToHalf(int)
*/
public static int halfToIntBits(@HalfFloat short h) {
- return (h & FP16_COMBINED) > FP16_EXPONENT_MAX ? NaN : h & 0xffff;
+ return (h & FP16.EXPONENT_SIGNIFICAND_MASK) > FP16.POSITIVE_INFINITY ? NaN : h & 0xffff;
}
/**
@@ -505,7 +479,7 @@
* of the second parameter
*/
public static @HalfFloat short copySign(@HalfFloat short magnitude, @HalfFloat short sign) {
- return (short) ((sign & FP16_SIGN_MASK) | (magnitude & FP16_COMBINED));
+ return (short) ((sign & FP16.SIGN_MASK) | (magnitude & FP16.EXPONENT_SIGNIFICAND_MASK));
}
/**
@@ -523,7 +497,7 @@
* @return The absolute value of the specified half-precision float
*/
public static @HalfFloat short abs(@HalfFloat short h) {
- return (short) (h & FP16_COMBINED);
+ return (short) (h & FP16.EXPONENT_SIGNIFICAND_MASK);
}
/**
@@ -538,26 +512,18 @@
* the result is zero (with the same sign)</li>
* </ul>
*
+ * <p class=note>
+ * <strong>Note:</strong> Unlike the identically named
+ * <code class=prettyprint>int java.lang.Math.round(float)</code> method,
+ * this returns a Half value stored in a short, <strong>not</strong> an
+ * actual short integer result.
+ *
* @param h A half-precision float value
* @return The value of the specified half-precision float rounded to the nearest
* half-precision float value
*/
public static @HalfFloat short round(@HalfFloat short h) {
- int bits = h & 0xffff;
- int e = bits & 0x7fff;
- int result = bits;
-
- if (e < 0x3c00) {
- result &= FP16_SIGN_MASK;
- result |= (0x3c00 & (e >= 0x3800 ? 0xffff : 0x0));
- } else if (e < 0x6400) {
- e = 25 - (e >> 10);
- int mask = (1 << e) - 1;
- result += (1 << (e - 1));
- result &= ~mask;
- }
-
- return (short) result;
+ return FP16.rint(h);
}
/**
@@ -577,21 +543,7 @@
* greater than or equal to the specified half-precision float value
*/
public static @HalfFloat short ceil(@HalfFloat short h) {
- int bits = h & 0xffff;
- int e = bits & 0x7fff;
- int result = bits;
-
- if (e < 0x3c00) {
- result &= FP16_SIGN_MASK;
- result |= 0x3c00 & -(~(bits >> 15) & (e != 0 ? 1 : 0));
- } else if (e < 0x6400) {
- e = 25 - (e >> 10);
- int mask = (1 << e) - 1;
- result += mask & ((bits >> 15) - 1);
- result &= ~mask;
- }
-
- return (short) result;
+ return FP16.ceil(h);
}
/**
@@ -611,21 +563,7 @@
* less than or equal to the specified half-precision float value
*/
public static @HalfFloat short floor(@HalfFloat short h) {
- int bits = h & 0xffff;
- int e = bits & 0x7fff;
- int result = bits;
-
- if (e < 0x3c00) {
- result &= FP16_SIGN_MASK;
- result |= 0x3c00 & (bits > 0x8000 ? 0xffff : 0x0);
- } else if (e < 0x6400) {
- e = 25 - (e >> 10);
- int mask = (1 << e) - 1;
- result += mask & -(bits >> 15);
- result &= ~mask;
- }
-
- return (short) result;
+ return FP16.floor(h);
}
/**
@@ -644,19 +582,7 @@
* half-precision float value
*/
public static @HalfFloat short trunc(@HalfFloat short h) {
- int bits = h & 0xffff;
- int e = bits & 0x7fff;
- int result = bits;
-
- if (e < 0x3c00) {
- result &= FP16_SIGN_MASK;
- } else if (e < 0x6400) {
- e = 25 - (e >> 10);
- int mask = (1 << e) - 1;
- result &= ~mask;
- }
-
- return (short) result;
+ return FP16.trunc(h);
}
/**
@@ -672,15 +598,7 @@
* @return The smaller of the two specified half-precision values
*/
public static @HalfFloat short min(@HalfFloat short x, @HalfFloat short y) {
- if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return NaN;
- if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return NaN;
-
- if ((x & FP16_COMBINED) == 0 && (y & FP16_COMBINED) == 0) {
- return (x & FP16_SIGN_MASK) != 0 ? x : y;
- }
-
- return ((x & FP16_SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) <
- ((y & FP16_SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff) ? x : y;
+ return FP16.min(x, y);
}
/**
@@ -697,15 +615,7 @@
* @return The larger of the two specified half-precision values
*/
public static @HalfFloat short max(@HalfFloat short x, @HalfFloat short y) {
- if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return NaN;
- if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return NaN;
-
- if ((x & FP16_COMBINED) == 0 && (y & FP16_COMBINED) == 0) {
- return (x & FP16_SIGN_MASK) != 0 ? y : x;
- }
-
- return ((x & FP16_SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) >
- ((y & FP16_SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff) ? x : y;
+ return FP16.max(x, y);
}
/**
@@ -719,11 +629,7 @@
* @return True if x is less than y, false otherwise
*/
public static boolean less(@HalfFloat short x, @HalfFloat short y) {
- if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return false;
- if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return false;
-
- return ((x & FP16_SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) <
- ((y & FP16_SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff);
+ return FP16.less(x, y);
}
/**
@@ -737,11 +643,7 @@
* @return True if x is less than or equal to y, false otherwise
*/
public static boolean lessEquals(@HalfFloat short x, @HalfFloat short y) {
- if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return false;
- if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return false;
-
- return ((x & FP16_SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) <=
- ((y & FP16_SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff);
+ return FP16.lessEquals(x, y);
}
/**
@@ -755,11 +657,7 @@
* @return True if x is greater than y, false otherwise
*/
public static boolean greater(@HalfFloat short x, @HalfFloat short y) {
- if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return false;
- if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return false;
-
- return ((x & FP16_SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) >
- ((y & FP16_SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff);
+ return FP16.greater(x, y);
}
/**
@@ -773,11 +671,7 @@
* @return True if x is greater than y, false otherwise
*/
public static boolean greaterEquals(@HalfFloat short x, @HalfFloat short y) {
- if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return false;
- if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return false;
-
- return ((x & FP16_SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) >=
- ((y & FP16_SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff);
+ return FP16.greaterEquals(x, y);
}
/**
@@ -791,10 +685,7 @@
* @return True if x is equal to y, false otherwise
*/
public static boolean equals(@HalfFloat short x, @HalfFloat short y) {
- if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return false;
- if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return false;
-
- return x == y || ((x | y) & FP16_COMBINED) == 0;
+ return FP16.equals(x, y);
}
/**
@@ -804,7 +695,7 @@
* @return 1 if the value is positive, -1 if the value is negative
*/
public static int getSign(@HalfFloat short h) {
- return (h & FP16_SIGN_MASK) == 0 ? 1 : -1;
+ return (h & FP16.SIGN_MASK) == 0 ? 1 : -1;
}
/**
@@ -818,7 +709,7 @@
* @return The unbiased exponent of the specified value
*/
public static int getExponent(@HalfFloat short h) {
- return ((h >>> FP16_EXPONENT_SHIFT) & FP16_EXPONENT_MASK) - FP16_EXPONENT_BIAS;
+ return ((h >>> FP16.EXPONENT_SHIFT) & FP16.SHIFTED_EXPONENT_MASK) - FP16.EXPONENT_BIAS;
}
/**
@@ -829,7 +720,7 @@
* @return The significand, or significand, of the specified vlaue
*/
public static int getSignificand(@HalfFloat short h) {
- return h & FP16_SIGNIFICAND_MASK;
+ return h & FP16.SIGNIFICAND_MASK;
}
/**
@@ -841,7 +732,7 @@
* false otherwise
*/
public static boolean isInfinite(@HalfFloat short h) {
- return (h & FP16_COMBINED) == FP16_EXPONENT_MAX;
+ return FP16.isInfinite(h);
}
/**
@@ -852,7 +743,7 @@
* @return True if the value is a NaN, false otherwise
*/
public static boolean isNaN(@HalfFloat short h) {
- return (h & FP16_COMBINED) > FP16_EXPONENT_MAX;
+ return FP16.isNaN(h);
}
/**
@@ -866,7 +757,7 @@
* @return True if the value is normalized, false otherwise
*/
public static boolean isNormalized(@HalfFloat short h) {
- return (h & FP16_EXPONENT_MAX) != 0 && (h & FP16_EXPONENT_MAX) != FP16_EXPONENT_MAX;
+ return FP16.isNormalized(h);
}
/**
@@ -885,35 +776,7 @@
* @return A normalized single-precision float value
*/
public static float toFloat(@HalfFloat short h) {
- int bits = h & 0xffff;
- int s = bits & FP16_SIGN_MASK;
- int e = (bits >>> FP16_EXPONENT_SHIFT) & FP16_EXPONENT_MASK;
- int m = (bits ) & FP16_SIGNIFICAND_MASK;
-
- int outE = 0;
- int outM = 0;
-
- if (e == 0) { // Denormal or 0
- if (m != 0) {
- // Convert denorm fp16 into normalized fp32
- float o = Float.intBitsToFloat(FP32_DENORMAL_MAGIC + m);
- o -= FP32_DENORMAL_FLOAT;
- return s == 0 ? o : -o;
- }
- } else {
- outM = m << 13;
- if (e == 0x1f) { // Infinite or NaN
- outE = 0xff;
- if (outM != 0) { // SNaNs are quieted
- outM |= FP32_QNAN_MASK;
- }
- } else {
- outE = e - FP16_EXPONENT_BIAS + FP32_EXPONENT_BIAS;
- }
- }
-
- int out = (s << 16) | (outE << FP32_EXPONENT_SHIFT) | outM;
- return Float.intBitsToFloat(out);
+ return FP16.toFloat(h);
}
/**
@@ -940,44 +803,7 @@
*/
@SuppressWarnings("StatementWithEmptyBody")
public static @HalfFloat short toHalf(float f) {
- int bits = Float.floatToRawIntBits(f);
- int s = (bits >>> FP32_SIGN_SHIFT );
- int e = (bits >>> FP32_EXPONENT_SHIFT) & FP32_EXPONENT_MASK;
- int m = (bits ) & FP32_SIGNIFICAND_MASK;
-
- int outE = 0;
- int outM = 0;
-
- if (e == 0xff) { // Infinite or NaN
- outE = 0x1f;
- outM = m != 0 ? 0x200 : 0;
- } else {
- e = e - FP32_EXPONENT_BIAS + FP16_EXPONENT_BIAS;
- if (e >= 0x1f) { // Overflow
- outE = 0x31;
- } else if (e <= 0) { // Underflow
- if (e < -10) {
- // The absolute fp32 value is less than MIN_VALUE, flush to +/-0
- } else {
- // The fp32 value is a normalized float less than MIN_NORMAL,
- // we convert to a denorm fp16
- m = (m | 0x800000) >> (1 - e);
- if ((m & 0x1000) != 0) m += 0x2000;
- outM = m >> 13;
- }
- } else {
- outE = e;
- outM = m >> 13;
- if ((m & 0x1000) != 0) {
- // Round to nearest "0.5" up
- int out = (outE << FP16_EXPONENT_SHIFT) | outM;
- out++;
- return (short) (out | (s << FP16_SIGN_SHIFT));
- }
- }
- }
-
- return (short) ((s << FP16_SIGN_SHIFT) | (outE << FP16_EXPONENT_SHIFT) | outM);
+ return FP16.toHalf(f);
}
/**
@@ -1073,40 +899,6 @@
*/
@NonNull
public static String toHexString(@HalfFloat short h) {
- StringBuilder o = new StringBuilder();
-
- int bits = h & 0xffff;
- int s = (bits >>> FP16_SIGN_SHIFT );
- int e = (bits >>> FP16_EXPONENT_SHIFT) & FP16_EXPONENT_MASK;
- int m = (bits ) & FP16_SIGNIFICAND_MASK;
-
- if (e == 0x1f) { // Infinite or NaN
- if (m == 0) {
- if (s != 0) o.append('-');
- o.append("Infinity");
- } else {
- o.append("NaN");
- }
- } else {
- if (s == 1) o.append('-');
- if (e == 0) {
- if (m == 0) {
- o.append("0x0.0p0");
- } else {
- o.append("0x0.");
- String significand = Integer.toHexString(m);
- o.append(significand.replaceFirst("0{2,}$", ""));
- o.append("p-14");
- }
- } else {
- o.append("0x1.");
- String significand = Integer.toHexString(m);
- o.append(significand.replaceFirst("0{2,}$", ""));
- o.append('p');
- o.append(Integer.toString(e - FP16_EXPONENT_BIAS));
- }
- }
-
- return o.toString();
+ return FP16.toHexString(h);
}
}
diff --git a/core/java/android/util/LocalLog.java b/core/java/android/util/LocalLog.java
index 8b5659b..3a1df3e 100644
--- a/core/java/android/util/LocalLog.java
+++ b/core/java/android/util/LocalLog.java
@@ -60,9 +60,19 @@
}
public synchronized void dump(PrintWriter pw) {
+ dump("", pw);
+ }
+
+ /**
+ * Dumps the content of local log to print writer with each log entry predeced with indent
+ *
+ * @param indent indent that precedes each log entry
+ * @param pw printer writer to write into
+ */
+ public synchronized void dump(String indent, PrintWriter pw) {
Iterator<String> itr = mLog.iterator();
while (itr.hasNext()) {
- pw.println(itr.next());
+ pw.printf("%s%s\n", indent, itr.next());
}
}
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 00206fc..faeecda 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -164,6 +164,8 @@
public static final String LAUNCH_LOCATON_DIRECT_SHARE = "direct_share";
private static final int APP_PREDICTION_SHARE_TARGET_QUERY_PACKAGE_LIMIT = 20;
public static final String APP_PREDICTION_INTENT_FILTER_KEY = "intent_filter";
+
+ private boolean mIsAppPredictorComponentAvailable;
private AppPredictor mAppPredictor;
private AppPredictor.Callback mAppPredictorCallback;
private Map<ChooserTarget, AppTarget> mDirectShareAppTargetCache;
@@ -617,6 +619,9 @@
.addTaggedData(MetricsEvent.FIELD_SHARESHEET_MIMETYPE, target.getType())
.addTaggedData(MetricsEvent.FIELD_TIME_TO_APP_TARGETS, systemCost));
+ // This is the only place this value is being set. Effectively final.
+ mIsAppPredictorComponentAvailable = isAppPredictionServiceAvailable();
+
AppPredictor appPredictor = getAppPredictorForDirectShareIfEnabled();
if (appPredictor != null) {
mDirectShareAppTargetCache = new HashMap<>();
@@ -707,6 +712,32 @@
}
/**
+ * Returns true if app prediction service is defined and the component exists on device.
+ */
+ private boolean isAppPredictionServiceAvailable() {
+ final String appPredictionServiceName =
+ getString(R.string.config_defaultAppPredictionService);
+ if (appPredictionServiceName == null) {
+ return false;
+ }
+ final ComponentName appPredictionComponentName =
+ ComponentName.unflattenFromString(appPredictionServiceName);
+ if (appPredictionComponentName == null) {
+ return false;
+ }
+
+ // Check if the app prediction component actually exists on the device.
+ Intent intent = new Intent();
+ intent.setComponent(appPredictionComponentName);
+ if (getPackageManager().resolveService(intent, PackageManager.MATCH_ALL) == null) {
+ Log.e(TAG, "App prediction service is defined, but does not exist: "
+ + appPredictionServiceName);
+ return false;
+ }
+ return true;
+ }
+
+ /**
* Check if the profile currently used is a work profile.
* @return true if it is work profile, false if it is parent profile (or no work profile is
* set up)
@@ -1693,6 +1724,9 @@
@Nullable
private AppPredictor getAppPredictor() {
+ if (!mIsAppPredictorComponentAvailable) {
+ return null;
+ }
if (mAppPredictor == null
&& getPackageManager().getAppPredictionServicePackageName() != null) {
final IntentFilter filter = getTargetIntentFilter();
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index cf0394d..9441825 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -153,7 +153,7 @@
// Used to show the dialog when BiometricService starts authentication
void showBiometricDialog(in Bundle bundle, IBiometricServiceReceiverInternal receiver, int type,
- boolean requireConfirmation, int userId);
+ boolean requireConfirmation, int userId, String opPackageName);
// Used to hide the dialog when a biometric is authenticated
void onBiometricAuthenticated(boolean authenticated, String failureReason);
// Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 85ae18e..4c3a177 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -101,7 +101,7 @@
// Used to show the dialog when BiometricService starts authentication
void showBiometricDialog(in Bundle bundle, IBiometricServiceReceiverInternal receiver, int type,
- boolean requireConfirmation, int userId);
+ boolean requireConfirmation, int userId, String opPackageName);
// Used to hide the dialog when a biometric is authenticated
void onBiometricAuthenticated(boolean authenticated, String failureReason);
// Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc
diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
index c73de8f..1bb2ba2 100644
--- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java
+++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
@@ -775,17 +775,54 @@
return false;
}
+ private boolean performAccessibilityActionCommon(int action) {
+ switch (action) {
+ case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD:
+ case AccessibilityNodeInfo.ACTION_EXPAND:
+ case R.id.accessibilityActionScrollDown:
+ if (mCollapseOffset != 0) {
+ smoothScrollTo(0, 0);
+ return true;
+ }
+ break;
+ case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD:
+ case R.id.accessibilityActionScrollUp:
+ if (mCollapseOffset < mCollapsibleHeight) {
+ smoothScrollTo(mCollapsibleHeight, 0);
+ return true;
+ } else if ((mCollapseOffset < mCollapsibleHeight + mUncollapsibleHeight)
+ && isDismissable()) {
+ smoothScrollTo(mCollapsibleHeight + mUncollapsibleHeight, 0);
+ mDismissOnScrollerFinished = true;
+ return true;
+ }
+ break;
+ case AccessibilityNodeInfo.ACTION_COLLAPSE:
+ if (mCollapseOffset < mCollapsibleHeight) {
+ smoothScrollTo(mCollapsibleHeight, 0);
+ return true;
+ }
+ break;
+ case AccessibilityNodeInfo.ACTION_DISMISS:
+ if ((mCollapseOffset < mCollapsibleHeight + mUncollapsibleHeight)
+ && isDismissable()) {
+ smoothScrollTo(mCollapsibleHeight + mUncollapsibleHeight, 0);
+ mDismissOnScrollerFinished = true;
+ return true;
+ }
+ break;
+ }
+
+ return false;
+ }
+
@Override
public boolean onNestedPrePerformAccessibilityAction(View target, int action, Bundle args) {
if (super.onNestedPrePerformAccessibilityAction(target, action, args)) {
return true;
}
- if (action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD && mCollapseOffset != 0) {
- smoothScrollTo(0, 0);
- return true;
- }
- return false;
+ return performAccessibilityActionCommon(action);
}
@Override
@@ -802,9 +839,23 @@
if (isEnabled()) {
if (mCollapseOffset != 0) {
- info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
+ info.addAction(AccessibilityAction.ACTION_SCROLL_FORWARD);
+ info.addAction(AccessibilityAction.ACTION_EXPAND);
+ info.addAction(AccessibilityAction.ACTION_SCROLL_DOWN);
info.setScrollable(true);
}
+ if ((mCollapseOffset < mCollapsibleHeight + mUncollapsibleHeight)
+ && ((mCollapseOffset < mCollapsibleHeight) || isDismissable())) {
+ info.addAction(AccessibilityAction.ACTION_SCROLL_BACKWARD);
+ info.addAction(AccessibilityAction.ACTION_SCROLL_UP);
+ info.setScrollable(true);
+ }
+ if (mCollapseOffset < mCollapsibleHeight) {
+ info.addAction(AccessibilityAction.ACTION_COLLAPSE);
+ }
+ if (mCollapseOffset < mCollapsibleHeight + mUncollapsibleHeight && isDismissable()) {
+ info.addAction(AccessibilityAction.ACTION_DISMISS);
+ }
}
// This view should never get accessibility focus, but it's interactive
@@ -823,12 +874,7 @@
return true;
}
- if (action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD && mCollapseOffset != 0) {
- smoothScrollTo(0, 0);
- return true;
- }
-
- return false;
+ return performAccessibilityActionCommon(action);
}
@Override
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 78e8e13..18a1b43 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -237,10 +237,6 @@
}
void imageInfo(JNIEnv* env, jobject bitmap, AndroidBitmapInfo* info) {
- SkASSERT(info);
- SkASSERT(env);
- SkASSERT(bitmap);
- SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class));
jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr);
LocalScopedBitmap localBitmap(bitmapHandle);
@@ -262,6 +258,9 @@
case kAlpha_8_SkColorType:
info->format = ANDROID_BITMAP_FORMAT_A_8;
break;
+ case kRGBA_F16_SkColorType:
+ info->format = ANDROID_BITMAP_FORMAT_RGBA_F16;
+ break;
default:
info->format = ANDROID_BITMAP_FORMAT_NONE;
break;
diff --git a/core/jni/android/graphics/ImageDecoder.cpp b/core/jni/android/graphics/ImageDecoder.cpp
index 98162af..ec91cbf 100644
--- a/core/jni/android/graphics/ImageDecoder.cpp
+++ b/core/jni/android/graphics/ImageDecoder.cpp
@@ -78,14 +78,18 @@
return nullptr;
}
-static jobject native_create(JNIEnv* env, std::unique_ptr<SkStream> stream, jobject source) {
+static jobject native_create(JNIEnv* env, std::unique_ptr<SkStream> stream,
+ jobject source, jboolean preferAnimation) {
if (!stream.get()) {
return throw_exception(env, ImageDecoder::kSourceMalformedData, "Failed to create a stream",
nullptr, source);
}
std::unique_ptr<ImageDecoder> decoder(new ImageDecoder);
SkCodec::Result result;
- auto codec = SkCodec::MakeFromStream(std::move(stream), &result, decoder->mPeeker.get());
+ auto codec = SkCodec::MakeFromStream(
+ std::move(stream), &result, decoder->mPeeker.get(),
+ preferAnimation ? SkCodec::SelectionPolicy::kPreferAnimation
+ : SkCodec::SelectionPolicy::kPreferStillImage);
if (jthrowable jexception = get_and_clear_exception(env)) {
return throw_exception(env, ImageDecoder::kSourceException, "", jexception, source);
}
@@ -124,7 +128,7 @@
}
static jobject ImageDecoder_nCreateFd(JNIEnv* env, jobject /*clazz*/,
- jobject fileDescriptor, jobject source) {
+ jobject fileDescriptor, jboolean preferAnimation, jobject source) {
int descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);
struct stat fdStat;
@@ -142,11 +146,11 @@
}
std::unique_ptr<SkFILEStream> fileStream(new SkFILEStream(file));
- return native_create(env, std::move(fileStream), source);
+ return native_create(env, std::move(fileStream), source, preferAnimation);
}
static jobject ImageDecoder_nCreateInputStream(JNIEnv* env, jobject /*clazz*/,
- jobject is, jbyteArray storage, jobject source) {
+ jobject is, jbyteArray storage, jboolean preferAnimation, jobject source) {
std::unique_ptr<SkStream> stream(CreateJavaInputStreamAdaptor(env, is, storage, false));
if (!stream.get()) {
@@ -157,31 +161,33 @@
std::unique_ptr<SkStream> bufferedStream(
SkFrontBufferedStream::Make(std::move(stream),
SkCodec::MinBufferedBytesNeeded()));
- return native_create(env, std::move(bufferedStream), source);
+ return native_create(env, std::move(bufferedStream), source, preferAnimation);
}
-static jobject ImageDecoder_nCreateAsset(JNIEnv* env, jobject /*clazz*/, jlong assetPtr,
- jobject source) {
+static jobject ImageDecoder_nCreateAsset(JNIEnv* env, jobject /*clazz*/,
+ jlong assetPtr, jboolean preferAnimation, jobject source) {
Asset* asset = reinterpret_cast<Asset*>(assetPtr);
std::unique_ptr<SkStream> stream(new AssetStreamAdaptor(asset));
- return native_create(env, std::move(stream), source);
+ return native_create(env, std::move(stream), source, preferAnimation);
}
-static jobject ImageDecoder_nCreateByteBuffer(JNIEnv* env, jobject /*clazz*/, jobject jbyteBuffer,
- jint initialPosition, jint limit, jobject source) {
+static jobject ImageDecoder_nCreateByteBuffer(JNIEnv* env, jobject /*clazz*/,
+ jobject jbyteBuffer, jint initialPosition, jint limit,
+ jboolean preferAnimation, jobject source) {
std::unique_ptr<SkStream> stream = CreateByteBufferStreamAdaptor(env, jbyteBuffer,
initialPosition, limit);
if (!stream) {
return throw_exception(env, ImageDecoder::kSourceMalformedData, "Failed to read ByteBuffer",
nullptr, source);
}
- return native_create(env, std::move(stream), source);
+ return native_create(env, std::move(stream), source, preferAnimation);
}
-static jobject ImageDecoder_nCreateByteArray(JNIEnv* env, jobject /*clazz*/, jbyteArray byteArray,
- jint offset, jint length, jobject source) {
+static jobject ImageDecoder_nCreateByteArray(JNIEnv* env, jobject /*clazz*/,
+ jbyteArray byteArray, jint offset, jint length,
+ jboolean preferAnimation, jobject source) {
std::unique_ptr<SkStream> stream(CreateByteArrayStreamAdaptor(env, byteArray, offset, length));
- return native_create(env, std::move(stream), source);
+ return native_create(env, std::move(stream), source, preferAnimation);
}
jint postProcessAndRelease(JNIEnv* env, jobject jimageDecoder, std::unique_ptr<Canvas> canvas) {
@@ -514,11 +520,11 @@
}
static const JNINativeMethod gImageDecoderMethods[] = {
- { "nCreate", "(JLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateAsset },
- { "nCreate", "(Ljava/nio/ByteBuffer;IILandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteBuffer },
- { "nCreate", "([BIILandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteArray },
- { "nCreate", "(Ljava/io/InputStream;[BLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateInputStream },
- { "nCreate", "(Ljava/io/FileDescriptor;Landroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateFd },
+ { "nCreate", "(JZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateAsset },
+ { "nCreate", "(Ljava/nio/ByteBuffer;IIZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteBuffer },
+ { "nCreate", "([BIIZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteArray },
+ { "nCreate", "(Ljava/io/InputStream;[BZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateInputStream },
+ { "nCreate", "(Ljava/io/FileDescriptor;ZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateFd },
{ "nDecodeBitmap", "(JLandroid/graphics/ImageDecoder;ZIILandroid/graphics/Rect;ZIZZZJZ)Landroid/graphics/Bitmap;",
(void*) ImageDecoder_nDecodeBitmap },
{ "nGetSampledSize","(JI)Landroid/util/Size;", (void*) ImageDecoder_nGetSampledSize },
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 5cbf81c..096bf69 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -497,11 +497,8 @@
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
- std::vector<uint8_t> byteData(parcel->dataSize());
- memcpy(byteData.data(), parcel->data(), parcel->dataSize());
-
SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl*>(nativeObject);
- transaction->setMetadata(ctrl, id, std::move(byteData));
+ transaction->setMetadata(ctrl, id, *parcel);
}
static void nativeSetColor(JNIEnv* env, jclass clazz, jlong transactionObj,
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 795f7ab..d5b875b 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -117,7 +117,9 @@
static pid_t gSystemServerPid = 0;
+static constexpr const char* kPropFuse = "persist.sys.fuse";
static constexpr const char* kZygoteClassName = "com/android/internal/os/Zygote";
+
static jclass gZygoteClass;
static jmethodID gCallPostForkSystemServerHooks;
static jmethodID gCallPostForkChildHooks;
@@ -704,15 +706,24 @@
return;
}
- const std::string& storage_source = ExternalStorageViews[mount_mode];
-
- BindMount(storage_source, "/storage", fail_fn);
-
- // Mount user-specific symlink helper into place
- userid_t user_id = multiuser_get_user_id(uid);
+ const userid_t user_id = multiuser_get_user_id(uid);
const std::string user_source = StringPrintf("/mnt/user/%d", user_id);
+ bool isFuse = GetBoolProperty(kPropFuse, false);
+
CreateDir(user_source, 0751, AID_ROOT, AID_ROOT, fail_fn);
- BindMount(user_source, "/storage/self", fail_fn);
+
+ if (isFuse) {
+ // TODO(b/135341433): Bind mount the appropriate storage view for the app given its permissions
+ // media and media_location permission access. This should prevent the kernel from incorrectly
+ // sharing a cache across permission buckets
+ BindMount(user_source, "/storage", fail_fn);
+ } else {
+ const std::string& storage_source = ExternalStorageViews[mount_mode];
+ BindMount(storage_source, "/storage", fail_fn);
+
+ // Mount user-specific symlink helper into place
+ BindMount(user_source, "/storage/self", fail_fn);
+ }
}
static bool NeedsNoRandomizeWorkaround() {
diff --git a/core/proto/android/providers/settings.proto b/core/proto/android/providers/settings.proto
index e43b6a0..e62af74 100644
--- a/core/proto/android/providers/settings.proto
+++ b/core/proto/android/providers/settings.proto
@@ -20,6 +20,7 @@
option java_multiple_files = true;
option java_outer_classname = "SettingsServiceProto";
+import "frameworks/base/core/proto/android/providers/settings/config.proto";
import "frameworks/base/core/proto/android/providers/settings/global.proto";
import "frameworks/base/core/proto/android/providers/settings/secure.proto";
import "frameworks/base/core/proto/android/providers/settings/system.proto";
@@ -33,6 +34,9 @@
// Global settings
optional GlobalSettingsProto global_settings = 2;
+
+ // Config settings
+ optional ConfigSettingsProto config_settings = 3;
}
message UserSettingsProto {
diff --git a/core/proto/android/providers/settings/config.proto b/core/proto/android/providers/settings/config.proto
new file mode 100644
index 0000000..cc24196
--- /dev/null
+++ b/core/proto/android/providers/settings/config.proto
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+package android.providers.settings;
+
+option java_multiple_files = true;
+
+import "frameworks/base/core/proto/android/providers/settings/common.proto";
+import "frameworks/base/core/proto/android/privacy.proto";
+
+message ConfigSettingsProto {
+ option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+ repeated SettingsOperationProto historical_operations = 1;
+ repeated NamespaceProto extra_namespaces = 2;
+ repeated SettingProto activity_manager_native_boot_settings = 3;
+ repeated SettingProto activity_manager_settings = 4;
+ repeated SettingProto app_compat_settings = 5;
+ repeated SettingProto autofill_settings = 6;
+ repeated SettingProto connectivity_settings = 7;
+ repeated SettingProto content_capture_settings = 8;
+ repeated SettingProto dex_boot_settings = 9;
+ repeated SettingProto game_driver_settings = 10;
+ repeated SettingProto input_native_boot_settings = 11;
+ repeated SettingProto netd_native_settings = 12;
+ repeated SettingProto privacy_settings = 13;
+ repeated SettingProto rollback_boot_settings = 14;
+ repeated SettingProto rollback_settings = 15;
+ repeated SettingProto runtime_native_boot_settings = 16;
+ repeated SettingProto runtime_native_settings = 17;
+ repeated SettingProto runtime_settings = 18;
+ repeated SettingProto storage_settings = 19;
+ repeated SettingProto systemui_settings = 20;
+ repeated SettingProto telephony_settings = 21;
+ repeated SettingProto textclassifier_settings = 22;
+
+ message NamespaceProto {
+ optional string namespace = 1;
+ repeated SettingProto settings = 2;
+ }
+}
\ No newline at end of file
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index 41a5140..f2ca0a4 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -1013,7 +1013,7 @@
optional SettingProto watchdog_poor_network_test_enabled = 22 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto suspend_optimizations_enabled = 23 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto verbose_logging_enabled = 24 [ (android.privacy).dest = DEST_AUTOMATIC ];
- reserved 25; // connected_mac_randomization_enabled
+ reserved 25; reserved "connected_mac_randomization_enabled";
optional SettingProto max_dhcp_retry_count = 26 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto mobile_data_transition_wakelock_timeout_ms = 27 [ (android.privacy).dest = DEST_AUTOMATIC ];
// Controls whether WiFi configurations created by a Device Owner app should
@@ -1025,7 +1025,7 @@
optional SettingProto device_owner_configs_lockdown = 28 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto frequency_band = 29 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto p2p_device_name = 30;
- optional SettingProto reenable_delay_ms = 31 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ reserved 31; reserved "reenable_delay_ms";
optional SettingProto ephemeral_out_of_range_timeout_ms = 32 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto on_when_proxy_disconnected = 33 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto bounce_delay_override_ms = 34 [ (android.privacy).dest = DEST_AUTOMATIC ];
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index fa4e085..ceccd0d 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1707,6 +1707,7 @@
manifest. -->
<string-array name="config_forceQueryablePackages" translatable="false">
<item>com.android.settings</item>
+ <item>com.android.providers.settings</item>
<!-- Add packages here -->
</string-array>
@@ -4285,4 +4286,9 @@
<!-- The list of packages to automatically opt out of refresh rates higher than 60hz because
of known compatibility issues. -->
<string-array name="config_highRefreshRateBlacklist"></string-array>
+
+ <!-- Whether or not to hide the navigation bar when the soft keyboard is visible in order to
+ create additional screen real estate outside beyond the keyboard. Note that the user needs
+ to have a confirmed way to dismiss the keyboard when desired. -->
+ <bool name="config_automotiveHideNavBarForKeyboard">false</bool>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 228c0a1..c37a457 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3846,4 +3846,6 @@
<java-symbol type="string" name="config_factoryResetPackage" />
<java-symbol type="array" name="config_highRefreshRateBlacklist" />
+ <java-symbol type="bool" name="config_automotiveHideNavBarForKeyboard" />
+
</resources>
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java
index 3d9a1d9..7c6271c 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java
@@ -19,6 +19,7 @@
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -43,6 +44,7 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.stubbing.Answer;
+import org.mockito.verification.VerificationWithTimeout;
import java.util.Arrays;
import java.util.HashSet;
@@ -56,6 +58,8 @@
public class StartProgramListUpdatesFanoutTest {
private static final String TAG = "BroadcastRadioTests.hal2.StartProgramListUpdatesFanout";
+ private static final VerificationWithTimeout CB_TIMEOUT = timeout(100);
+
// Mocks
@Mock IBroadcastRadio mBroadcastRadioMock;
@Mock ITunerSession mHalTunerSessionMock;
@@ -200,10 +204,10 @@
// Adding mDabEnsembleInfo should not update any client.
updateHalProgramInfo(false, Arrays.asList(mDabEnsembleInfo), null);
- verify(mAidlTunerCallbackMocks[0], times(1)).onProgramListUpdated(any());
- verify(mAidlTunerCallbackMocks[1], times(2)).onProgramListUpdated(any());
- verify(mAidlTunerCallbackMocks[2], times(1)).onProgramListUpdated(any());
- verify(mAidlTunerCallbackMocks[3], times(2)).onProgramListUpdated(any());
+ verify(mAidlTunerCallbackMocks[0], CB_TIMEOUT.times(1)).onProgramListUpdated(any());
+ verify(mAidlTunerCallbackMocks[1], CB_TIMEOUT.times(2)).onProgramListUpdated(any());
+ verify(mAidlTunerCallbackMocks[2], CB_TIMEOUT.times(1)).onProgramListUpdated(any());
+ verify(mAidlTunerCallbackMocks[3], CB_TIMEOUT.times(2)).onProgramListUpdated(any());
}
@Test
@@ -240,7 +244,7 @@
// Update the HAL with mModifiedAmFmInfo, and verify only the remaining client is updated.
updateHalProgramInfo(true, Arrays.asList(mModifiedAmFmInfo), null);
- verify(mAidlTunerCallbackMocks[0], times(1)).onProgramListUpdated(any());
+ verify(mAidlTunerCallbackMocks[0], CB_TIMEOUT.times(1)).onProgramListUpdated(any());
verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[1], true,
Arrays.asList(mModifiedAmFmInfo), null);
@@ -313,6 +317,6 @@
}
ProgramList.Chunk expectedChunk = new ProgramList.Chunk(purge, true, modifiedSet,
removedSet);
- verify(clientMock).onProgramListUpdated(expectedChunk);
+ verify(clientMock, CB_TIMEOUT).onProgramListUpdated(expectedChunk);
}
}
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index bdbf368..97b7ae9 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -544,7 +544,6 @@
Settings.Global.WIFI_ON,
Settings.Global.WIFI_P2P_DEVICE_NAME,
Settings.Global.WIFI_P2P_PENDING_FACTORY_RESET,
- Settings.Global.WIFI_REENABLE_DELAY_MS,
Settings.Global.WIFI_RTT_BACKGROUND_EXEC_GAP_MS,
Settings.Global.WIFI_SAVED_STATE,
Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE,
@@ -721,7 +720,6 @@
Settings.Secure.BIOMETRIC_DEBUG_ENABLED,
Settings.Secure.FACE_UNLOCK_ATTENTION_REQUIRED,
Settings.Secure.FACE_UNLOCK_DIVERSITY_REQUIRED,
- Settings.Secure.FACE_UNLOCK_EDUCATION_INFO_DISPLAYED,
Settings.Secure.MANAGED_PROVISIONING_DPC_DOWNLOADED);
@Test
diff --git a/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java b/core/tests/coretests/src/android/provider/settings/validators/SettingsValidatorsTest.java
similarity index 85%
rename from core/tests/coretests/src/android/provider/SettingsValidatorsTest.java
rename to core/tests/coretests/src/android/provider/settings/validators/SettingsValidatorsTest.java
index eea8c83..5f042d3 100644
--- a/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java
+++ b/core/tests/coretests/src/android/provider/settings/validators/SettingsValidatorsTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.provider;
+package android.provider.settings.validators;
import static com.google.common.truth.Truth.assertThat;
@@ -23,7 +23,7 @@
import static org.junit.Assert.fail;
import android.platform.test.annotations.Presubmit;
-import android.provider.SettingsValidators.Validator;
+import android.provider.Settings;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -138,7 +138,7 @@
@Test
public void testDiscreteValueValidator() {
String[] beerTypes = new String[]{"Ale", "American IPA", "Stout"};
- Validator v = new SettingsValidators.DiscreteValueValidator(beerTypes);
+ Validator v = new DiscreteValueValidator(beerTypes);
assertTrue(v.validate("Ale"));
assertTrue(v.validate("American IPA"));
assertTrue(v.validate("Stout"));
@@ -148,14 +148,14 @@
@Test
public void testDiscreteValueValidator_onNullValue_returnsFalse() {
String[] discreteTypes = new String[]{"Type1", "Type2"};
- Validator v = new SettingsValidators.DiscreteValueValidator(discreteTypes);
+ Validator v = new DiscreteValueValidator(discreteTypes);
assertFalse(v.validate(null));
}
@Test
public void testInclusiveIntegerRangeValidator() {
- Validator v = new SettingsValidators.InclusiveIntegerRangeValidator(0, 5);
+ Validator v = new InclusiveIntegerRangeValidator(0, 5);
assertTrue(v.validate("0"));
assertTrue(v.validate("2"));
assertTrue(v.validate("5"));
@@ -165,14 +165,14 @@
@Test
public void testInclusiveIntegerRangeValidator_onNullValue_returnsFalse() {
- Validator v = new SettingsValidators.InclusiveIntegerRangeValidator(0, 5);
+ Validator v = new InclusiveIntegerRangeValidator(0, 5);
assertFalse(v.validate(null));
}
@Test
public void testInclusiveFloatRangeValidator() {
- Validator v = new SettingsValidators.InclusiveFloatRangeValidator(0.0f, 5.0f);
+ Validator v = new InclusiveFloatRangeValidator(0.0f, 5.0f);
assertTrue(v.validate("0.0"));
assertTrue(v.validate("2.0"));
assertTrue(v.validate("5.0"));
@@ -182,14 +182,14 @@
@Test
public void testInclusiveFloatRangeValidator_onNullValue_returnsFalse() {
- Validator v = new SettingsValidators.InclusiveFloatRangeValidator(0.0f, 5.0f);
+ Validator v = new InclusiveFloatRangeValidator(0.0f, 5.0f);
assertFalse(v.validate(null));
}
@Test
public void testComponentNameListValidator() {
- Validator v = new SettingsValidators.ComponentNameListValidator(",");
+ Validator v = new ComponentNameListValidator(",");
assertTrue(v.validate("com.android.localtransport/.LocalTransport,"
+ "com.google.android.gms/.backup.migrate.service.D2dTransport"));
assertFalse(v.validate("com.google.5android,android"));
@@ -197,21 +197,21 @@
@Test
public void testComponentNameListValidator_onNullValue_returnsFalse() {
- Validator v = new SettingsValidators.ComponentNameListValidator(",");
+ Validator v = new ComponentNameListValidator(",");
assertFalse(v.validate(null));
}
@Test
public void testPackageNameListValidator() {
- Validator v = new SettingsValidators.PackageNameListValidator(",");
+ Validator v = new PackageNameListValidator(",");
assertTrue(v.validate("com.android.localtransport.LocalTransport,com.google.android.gms"));
assertFalse(v.validate("5com.android.internal.backup.LocalTransport,android"));
}
@Test
public void testPackageNameListValidator_onNullValue_returnsFalse() {
- Validator v = new SettingsValidators.PackageNameListValidator(",");
+ Validator v = new PackageNameListValidator(",");
assertFalse(v.validate(null));
}
@@ -256,51 +256,41 @@
@Test
public void testTTSListValidator_withValidInput_returnsTrue() {
- Validator v = new SettingsValidators.TTSListValidator();
-
- assertTrue(v.validate("com.foo.ttsengine:en-US,com.bar.ttsengine:es_ES"));
+ assertTrue(
+ SettingsValidators.TTS_LIST_VALIDATOR.validate(
+ "com.foo.ttsengine:en-US,com.bar.ttsengine:es_ES"));
}
@Test
public void testTTSListValidator_withInvalidInput_returnsFalse() {
- Validator v = new SettingsValidators.TTSListValidator();
-
- assertFalse(v.validate("com.foo.ttsengine:eng-USA,INVALID"));
+ assertFalse(
+ SettingsValidators.TTS_LIST_VALIDATOR.validate(
+ "com.foo.ttsengine:eng-USA,INVALID"));
}
@Test
public void testTTSListValidator_withEmptyInput_returnsFalse() {
- Validator v = new SettingsValidators.TTSListValidator();
-
- assertFalse(v.validate(""));
+ assertFalse(SettingsValidators.TTS_LIST_VALIDATOR.validate(""));
}
@Test
public void testTTSListValidator_withNullInput_returnsFalse() {
- Validator v = new SettingsValidators.TTSListValidator();
-
- assertFalse(v.validate(null));
+ assertFalse(SettingsValidators.TTS_LIST_VALIDATOR.validate(null));
}
@Test
public void testTileListValidator_withValidInput_returnsTrue() {
- Validator v = new SettingsValidators.TileListValidator();
-
- assertTrue(v.validate("1,2,3,4"));
+ assertTrue(SettingsValidators.TILE_LIST_VALIDATOR.validate("1,2,3,4"));
}
@Test
public void testTileListValidator_withMissingValue_returnsFalse() {
- Validator v = new SettingsValidators.TileListValidator();
-
- assertFalse(v.validate("1,,3"));
+ assertFalse(SettingsValidators.TILE_LIST_VALIDATOR.validate("1,,3"));
}
@Test
public void testTileListValidator_withNullInput_returnsFalse() {
- Validator v = new SettingsValidators.TileListValidator();
-
- assertFalse(v.validate(null));
+ assertFalse(SettingsValidators.TILE_LIST_VALIDATOR.validate(null));
}
@Test
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 4025a08..4187c80 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -24,6 +24,7 @@
<permission name="android.permission.PROVIDE_RESOLVER_RANKER_SERVICE" />
<permission name="android.permission.MONITOR_DEFAULT_SMS_PACKAGE" />
<permission name="android.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE" />
+ <permission name="android.permission.INTERACT_ACROSS_USERS" />
</privapp-permissions>
<privapp-permissions package="com.android.apps.tag">
@@ -350,4 +351,19 @@
<permission name="android.permission.MANAGE_DYNAMIC_SYSTEM"/>
</privapp-permissions>
+ <privapp-permissions package="com.android.server.wifistack">
+ <permission name="android.permission.CHANGE_CONFIGURATION"/>
+ <permission name="android.permission.CONNECTIVITY_INTERNAL"/>
+ <permission name="android.permission.DUMP"/>
+ <permission name="android.permission.INTERACT_ACROSS_USERS"/>
+ <permission name="android.permission.LOCAL_MAC_ADDRESS"/>
+ <permission name="android.permission.MANAGE_USERS"/>
+ <permission name="android.permission.PACKAGE_USAGE_STATS"/>
+ <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
+ <permission name="android.permission.REQUEST_NETWORK_SCORES"/>
+ <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
+ <permission name="android.permission.UPDATE_DEVICE_STATS"/>
+ <permission name="android.permission.UPDATE_APP_OPS_STATS"/>
+ <permission name="android.permission.LOCATION_HARDWARE"/>
+ </privapp-permissions>
</permissions>
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index 2d5babc..150a941 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -214,7 +214,7 @@
/* @hide */
@NonNull
- abstract ImageDecoder createImageDecoder() throws IOException;
+ abstract ImageDecoder createImageDecoder(boolean preferAnimation) throws IOException;
};
private static class ByteArraySource extends Source {
@@ -228,8 +228,8 @@
private final int mLength;
@Override
- public ImageDecoder createImageDecoder() throws IOException {
- return nCreate(mData, mOffset, mLength, this);
+ public ImageDecoder createImageDecoder(boolean preferAnimation) throws IOException {
+ return nCreate(mData, mOffset, mLength, preferAnimation, this);
}
}
@@ -240,14 +240,14 @@
private final ByteBuffer mBuffer;
@Override
- public ImageDecoder createImageDecoder() throws IOException {
+ public ImageDecoder createImageDecoder(boolean preferAnimation) throws IOException {
if (!mBuffer.isDirect() && mBuffer.hasArray()) {
int offset = mBuffer.arrayOffset() + mBuffer.position();
int length = mBuffer.limit() - mBuffer.position();
- return nCreate(mBuffer.array(), offset, length, this);
+ return nCreate(mBuffer.array(), offset, length, preferAnimation, this);
}
ByteBuffer buffer = mBuffer.slice();
- return nCreate(buffer, buffer.position(), buffer.limit(), this);
+ return nCreate(buffer, buffer.position(), buffer.limit(), preferAnimation, this);
}
}
@@ -267,7 +267,7 @@
Resources getResources() { return mResources; }
@Override
- public ImageDecoder createImageDecoder() throws IOException {
+ public ImageDecoder createImageDecoder(boolean preferAnimation) throws IOException {
AssetFileDescriptor assetFd = null;
try {
if (mUri.getScheme() == ContentResolver.SCHEME_CONTENT) {
@@ -284,26 +284,26 @@
throw new FileNotFoundException(mUri.toString());
}
- return createFromStream(is, true, this);
+ return createFromStream(is, true, preferAnimation, this);
}
- return createFromAssetFileDescriptor(assetFd, this);
+ return createFromAssetFileDescriptor(assetFd, preferAnimation, this);
}
}
@NonNull
private static ImageDecoder createFromFile(@NonNull File file,
- @NonNull Source source) throws IOException {
+ boolean preferAnimation, @NonNull Source source) throws IOException {
FileInputStream stream = new FileInputStream(file);
FileDescriptor fd = stream.getFD();
try {
Os.lseek(fd, 0, SEEK_CUR);
} catch (ErrnoException e) {
- return createFromStream(stream, true, source);
+ return createFromStream(stream, true, preferAnimation, source);
}
ImageDecoder decoder = null;
try {
- decoder = nCreate(fd, source);
+ decoder = nCreate(fd, preferAnimation, source);
} finally {
if (decoder == null) {
IoUtils.closeQuietly(stream);
@@ -317,12 +317,12 @@
@NonNull
private static ImageDecoder createFromStream(@NonNull InputStream is,
- boolean closeInputStream, Source source) throws IOException {
+ boolean closeInputStream, boolean preferAnimation, Source source) throws IOException {
// Arbitrary size matches BitmapFactory.
byte[] storage = new byte[16 * 1024];
ImageDecoder decoder = null;
try {
- decoder = nCreate(is, storage, source);
+ decoder = nCreate(is, storage, preferAnimation, source);
} finally {
if (decoder == null) {
if (closeInputStream) {
@@ -340,7 +340,7 @@
@NonNull
private static ImageDecoder createFromAssetFileDescriptor(@NonNull AssetFileDescriptor assetFd,
- Source source) throws IOException {
+ boolean preferAnimation, Source source) throws IOException {
final FileDescriptor fd = assetFd.getFileDescriptor();
final long offset = assetFd.getStartOffset();
@@ -348,9 +348,9 @@
try {
try {
Os.lseek(fd, offset, SEEK_SET);
- decoder = nCreate(fd, source);
+ decoder = nCreate(fd, preferAnimation, source);
} catch (ErrnoException e) {
- decoder = createFromStream(new FileInputStream(fd), true, source);
+ decoder = createFromStream(new FileInputStream(fd), true, preferAnimation, source);
}
} finally {
if (decoder == null) {
@@ -388,7 +388,7 @@
public int getDensity() { return mInputDensity; }
@Override
- public ImageDecoder createImageDecoder() throws IOException {
+ public ImageDecoder createImageDecoder(boolean preferAnimation) throws IOException {
synchronized (this) {
if (mInputStream == null) {
@@ -396,7 +396,7 @@
}
InputStream is = mInputStream;
mInputStream = null;
- return createFromStream(is, false, this);
+ return createFromStream(is, false, preferAnimation, this);
}
}
}
@@ -434,14 +434,14 @@
}
@Override
- public ImageDecoder createImageDecoder() throws IOException {
+ public ImageDecoder createImageDecoder(boolean preferAnimation) throws IOException {
synchronized (this) {
if (mAssetInputStream == null) {
throw new IOException("Cannot reuse AssetInputStreamSource");
}
AssetInputStream ais = mAssetInputStream;
mAssetInputStream = null;
- return createFromAsset(ais, this);
+ return createFromAsset(ais, preferAnimation, this);
}
}
}
@@ -469,7 +469,7 @@
}
@Override
- public ImageDecoder createImageDecoder() throws IOException {
+ public ImageDecoder createImageDecoder(boolean preferAnimation) throws IOException {
TypedValue value = new TypedValue();
// This is just used in order to access the underlying Asset and
// keep it alive.
@@ -483,7 +483,7 @@
}
}
- return createFromAsset((AssetInputStream) is, this);
+ return createFromAsset((AssetInputStream) is, preferAnimation, this);
}
}
@@ -491,11 +491,11 @@
* ImageDecoder will own the AssetInputStream.
*/
private static ImageDecoder createFromAsset(AssetInputStream ais,
- Source source) throws IOException {
+ boolean preferAnimation, Source source) throws IOException {
ImageDecoder decoder = null;
try {
long asset = ais.getNativeAsset();
- decoder = nCreate(asset, source);
+ decoder = nCreate(asset, preferAnimation, source);
} finally {
if (decoder == null) {
IoUtils.closeQuietly(ais);
@@ -517,9 +517,9 @@
private final String mFileName;
@Override
- public ImageDecoder createImageDecoder() throws IOException {
+ public ImageDecoder createImageDecoder(boolean preferAnimation) throws IOException {
InputStream is = mAssets.open(mFileName);
- return createFromAsset((AssetInputStream) is, this);
+ return createFromAsset((AssetInputStream) is, preferAnimation, this);
}
}
@@ -531,8 +531,8 @@
private final File mFile;
@Override
- public ImageDecoder createImageDecoder() throws IOException {
- return createFromFile(mFile, this);
+ public ImageDecoder createImageDecoder(boolean preferAnimation) throws IOException {
+ return createFromFile(mFile, preferAnimation, this);
}
}
@@ -544,7 +544,7 @@
private final Callable<AssetFileDescriptor> mCallable;
@Override
- public ImageDecoder createImageDecoder() throws IOException {
+ public ImageDecoder createImageDecoder(boolean preferAnimation) throws IOException {
AssetFileDescriptor assetFd = null;
try {
assetFd = mCallable.call();
@@ -555,7 +555,7 @@
throw new IOException(e);
}
}
- return createFromAssetFileDescriptor(assetFd, this);
+ return createFromAssetFileDescriptor(assetFd, preferAnimation, this);
}
}
@@ -1740,7 +1740,7 @@
@NonNull
private static Drawable decodeDrawableImpl(@NonNull Source src,
@Nullable OnHeaderDecodedListener listener) throws IOException {
- try (ImageDecoder decoder = src.createImageDecoder()) {
+ try (ImageDecoder decoder = src.createImageDecoder(true /*preferAnimation*/)) {
decoder.mSource = src;
decoder.callHeaderDecoded(listener, src);
@@ -1844,7 +1844,7 @@
@NonNull
private static Bitmap decodeBitmapImpl(@NonNull Source src,
@Nullable OnHeaderDecodedListener listener) throws IOException {
- try (ImageDecoder decoder = src.createImageDecoder()) {
+ try (ImageDecoder decoder = src.createImageDecoder(false /*preferAnimation*/)) {
decoder.mSource = src;
decoder.callHeaderDecoded(listener, src);
@@ -1971,15 +1971,17 @@
}
}
- private static native ImageDecoder nCreate(long asset, Source src) throws IOException;
- private static native ImageDecoder nCreate(ByteBuffer buffer, int position,
- int limit, Source src) throws IOException;
+ private static native ImageDecoder nCreate(long asset,
+ boolean preferAnimation, Source src) throws IOException;
+ private static native ImageDecoder nCreate(ByteBuffer buffer, int position, int limit,
+ boolean preferAnimation, Source src) throws IOException;
private static native ImageDecoder nCreate(byte[] data, int offset, int length,
- Source src) throws IOException;
+ boolean preferAnimation, Source src) throws IOException;
private static native ImageDecoder nCreate(InputStream is, byte[] storage,
- Source src) throws IOException;
+ boolean preferAnimation, Source src) throws IOException;
// The fd must be seekable.
- private static native ImageDecoder nCreate(FileDescriptor fd, Source src) throws IOException;
+ private static native ImageDecoder nCreate(FileDescriptor fd,
+ boolean preferAnimation, Source src) throws IOException;
@NonNull
private static native Bitmap nDecodeBitmap(long nativePtr,
@NonNull ImageDecoder decoder,
diff --git a/libs/hostgraphics/Android.bp b/libs/hostgraphics/Android.bp
index aedb752..e713b98 100644
--- a/libs/hostgraphics/Android.bp
+++ b/libs/hostgraphics/Android.bp
@@ -1,8 +1,15 @@
cc_library_host_static {
name: "libhostgraphics",
+ cflags: [
+ "-Wno-unused-parameter",
+ ],
+
srcs: [
":libui_host_common",
+ "Fence.cpp",
+ "HostBufferQueue.cpp",
+ "PublicFormat.cpp",
],
include_dirs: [
diff --git a/libs/hostgraphics/Fence.cpp b/libs/hostgraphics/Fence.cpp
new file mode 100644
index 0000000..9e54816
--- /dev/null
+++ b/libs/hostgraphics/Fence.cpp
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+#include <ui/Fence.h>
+
+namespace android {
+
+const sp<Fence> Fence::NO_FENCE = sp<Fence>(new Fence);
+
+} // namespace android
\ No newline at end of file
diff --git a/libs/hostgraphics/HostBufferQueue.cpp b/libs/hostgraphics/HostBufferQueue.cpp
new file mode 100644
index 0000000..ec30437
--- /dev/null
+++ b/libs/hostgraphics/HostBufferQueue.cpp
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+#include <gui/BufferQueue.h>
+
+namespace android {
+
+class HostBufferQueue : public IGraphicBufferProducer, public IGraphicBufferConsumer {
+public:
+ HostBufferQueue() : mWidth(0), mHeight(0) { }
+
+ virtual status_t setConsumerIsProtected(bool isProtected) { return OK; }
+
+ virtual status_t detachBuffer(int slot) { return OK; }
+
+ virtual status_t getReleasedBuffers(uint64_t* slotMask) { return OK; }
+
+ virtual status_t setDefaultBufferSize(uint32_t w, uint32_t h) {
+ mWidth = w;
+ mHeight = h;
+ mBuffer = sp<GraphicBuffer>(new GraphicBuffer(mWidth, mHeight));
+ return OK;
+ }
+
+ virtual status_t setDefaultBufferFormat(PixelFormat defaultFormat) { return OK; }
+
+ virtual status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace) { return OK; }
+
+ virtual status_t discardFreeBuffers() { return OK; }
+
+ virtual status_t acquireBuffer(BufferItem* buffer, nsecs_t presentWhen,
+ uint64_t maxFrameNumber = 0) {
+ buffer->mGraphicBuffer = mBuffer;
+ buffer->mSlot = 0;
+ return OK;
+ }
+
+ virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) { return OK; }
+
+ virtual status_t setConsumerUsageBits(uint64_t usage) { return OK; }
+private:
+ sp<GraphicBuffer> mBuffer;
+ uint32_t mWidth;
+ uint32_t mHeight;
+};
+
+void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
+ sp<IGraphicBufferConsumer>* outConsumer) {
+
+ sp<HostBufferQueue> obj(new HostBufferQueue());
+
+ *outProducer = obj;
+ *outConsumer = obj;
+}
+
+} // namespace android
diff --git a/libs/hostgraphics/PublicFormat.cpp b/libs/hostgraphics/PublicFormat.cpp
new file mode 100644
index 0000000..af6d273
--- /dev/null
+++ b/libs/hostgraphics/PublicFormat.cpp
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+#include <ui/PublicFormat.h>
+
+namespace android {
+
+android_dataspace mapPublicFormatToHalDataspace(PublicFormat f) {
+ return static_cast<android_dataspace>(0);
+}
+
+int mapPublicFormatToHalFormat(PublicFormat f) {
+ return static_cast<int>(f);
+}
+
+PublicFormat mapHalFormatDataspaceToPublicFormat(int format, android_dataspace dataSpace) {
+ return static_cast<PublicFormat>(format);
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/libs/hostgraphics/gui/BufferItem.h b/libs/hostgraphics/gui/BufferItem.h
new file mode 100644
index 0000000..01409e1
--- /dev/null
+++ b/libs/hostgraphics/gui/BufferItem.h
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_GUI_BUFFERITEM_H
+#define ANDROID_GUI_BUFFERITEM_H
+
+#include <ui/Fence.h>
+#include <ui/Rect.h>
+
+#include <system/graphics.h>
+
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+class Fence;
+class GraphicBuffer;
+
+// The only thing we need here for layoutlib is mGraphicBuffer. The rest of the fields are added
+// just to satisfy the calls from the android_media_ImageReader.h
+
+class BufferItem {
+public:
+ enum { INVALID_BUFFER_SLOT = -1 };
+
+ BufferItem() : mGraphicBuffer(nullptr), mFence(Fence::NO_FENCE) {}
+ ~BufferItem() {}
+
+ sp<GraphicBuffer> mGraphicBuffer;
+
+ sp<Fence> mFence;
+
+ Rect mCrop;
+
+ uint32_t mTransform;
+
+ uint32_t mScalingMode;
+
+ int64_t mTimestamp;
+
+ android_dataspace mDataSpace;
+
+ uint64_t mFrameNumber;
+
+ int mSlot;
+
+ bool mTransformToDisplayInverse;
+};
+
+}
+
+#endif // ANDROID_GUI_BUFFERITEM_H
diff --git a/libs/hostgraphics/gui/BufferItemConsumer.h b/libs/hostgraphics/gui/BufferItemConsumer.h
new file mode 100644
index 0000000..707b313
--- /dev/null
+++ b/libs/hostgraphics/gui/BufferItemConsumer.h
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_GUI_BUFFERITEMCONSUMER_H
+#define ANDROID_GUI_BUFFERITEMCONSUMER_H
+
+#include <utils/RefBase.h>
+
+#include <gui/ConsumerBase.h>
+#include <gui/IGraphicBufferConsumer.h>
+
+namespace android {
+
+class BufferItemConsumer : public ConsumerBase {
+public:
+ BufferItemConsumer(
+ const sp<IGraphicBufferConsumer>& consumer,
+ uint64_t consumerUsage,
+ int bufferCount,
+ bool controlledByApp) : mConsumer(consumer) {
+ }
+
+ status_t acquireBuffer(BufferItem *item, nsecs_t presentWhen, bool waitForFence = true) {
+ return mConsumer->acquireBuffer(item, presentWhen, 0);
+ }
+
+ status_t releaseBuffer(
+ const BufferItem &item, const sp<Fence>& releaseFence = Fence::NO_FENCE) { return OK; }
+
+ void setName(const String8& name) { }
+
+ void setFrameAvailableListener(const wp<FrameAvailableListener>& listener) { }
+
+ status_t setDefaultBufferSize(uint32_t width, uint32_t height) {
+ return mConsumer->setDefaultBufferSize(width, height);
+ }
+
+ status_t setDefaultBufferFormat(PixelFormat defaultFormat) {
+ return mConsumer->setDefaultBufferFormat(defaultFormat);
+ }
+
+ status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace) {
+ return mConsumer->setDefaultBufferDataSpace(defaultDataSpace);
+ }
+
+ void abandon() { }
+
+ status_t detachBuffer(int slot) { return OK; }
+
+ status_t discardFreeBuffers() { return OK; }
+
+ void freeBufferLocked(int slotIndex) { }
+
+ status_t addReleaseFenceLocked(
+ int slot, const sp<GraphicBuffer> graphicBuffer, const sp<Fence>& fence) { return OK; }
+private:
+ sp<IGraphicBufferConsumer> mConsumer;
+};
+
+} // namespace android
+
+#endif // ANDROID_GUI_BUFFERITEMCONSUMER_H
diff --git a/libs/hostgraphics/gui/BufferQueue.h b/libs/hostgraphics/gui/BufferQueue.h
new file mode 100644
index 0000000..aa3e726
--- /dev/null
+++ b/libs/hostgraphics/gui/BufferQueue.h
@@ -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.
+ */
+
+#ifndef ANDROID_GUI_BUFFERQUEUE_H
+#define ANDROID_GUI_BUFFERQUEUE_H
+
+#include <gui/BufferItem.h>
+#include <gui/IGraphicBufferConsumer.h>
+#include <gui/IGraphicBufferProducer.h>
+
+namespace android {
+
+class BufferQueue {
+public:
+ enum { INVALID_BUFFER_SLOT = BufferItem::INVALID_BUFFER_SLOT };
+ enum { NO_BUFFER_AVAILABLE = IGraphicBufferConsumer::NO_BUFFER_AVAILABLE };
+
+ static void createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
+ sp<IGraphicBufferConsumer>* outConsumer);
+};
+
+} // namespace android
+
+#endif // ANDROID_GUI_BUFFERQUEUE_H
diff --git a/libs/hostgraphics/gui/ConsumerBase.h b/libs/hostgraphics/gui/ConsumerBase.h
new file mode 100644
index 0000000..9002953
--- /dev/null
+++ b/libs/hostgraphics/gui/ConsumerBase.h
@@ -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.
+ */
+
+#ifndef ANDROID_GUI_CONSUMERBASE_H
+#define ANDROID_GUI_CONSUMERBASE_H
+
+#include <gui/BufferItem.h>
+
+#include <utils/RefBase.h>
+
+namespace android {
+
+class ConsumerBase : public virtual RefBase {
+public:
+ struct FrameAvailableListener : public virtual RefBase {
+ // See IConsumerListener::onFrame{Available,Replaced}
+ virtual void onFrameAvailable(const BufferItem& item) = 0;
+ virtual void onFrameReplaced(const BufferItem& /* item */) {}
+ };
+};
+
+} // namespace android
+
+#endif // ANDROID_GUI_CONSUMERBASE_H
\ No newline at end of file
diff --git a/libs/hostgraphics/gui/IGraphicBufferConsumer.h b/libs/hostgraphics/gui/IGraphicBufferConsumer.h
new file mode 100644
index 0000000..9eb67b2
--- /dev/null
+++ b/libs/hostgraphics/gui/IGraphicBufferConsumer.h
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <utils/RefBase.h>
+
+#include <ui/PixelFormat.h>
+
+#include <utils/Errors.h>
+
+namespace android {
+
+class BufferItem;
+class Fence;
+class GraphicBuffer;
+
+class IGraphicBufferConsumer : virtual public RefBase {
+public:
+ enum {
+ // Returned by releaseBuffer, after which the consumer must free any references to the
+ // just-released buffer that it might have.
+ STALE_BUFFER_SLOT = 1,
+ // Returned by dequeueBuffer if there are no pending buffers available.
+ NO_BUFFER_AVAILABLE,
+ // Returned by dequeueBuffer if it's too early for the buffer to be acquired.
+ PRESENT_LATER,
+ };
+
+ virtual status_t acquireBuffer(BufferItem* buffer, nsecs_t presentWhen,
+ uint64_t maxFrameNumber = 0) = 0;
+
+ virtual status_t detachBuffer(int slot) = 0;
+
+ virtual status_t getReleasedBuffers(uint64_t* slotMask) = 0;
+
+ virtual status_t setDefaultBufferSize(uint32_t w, uint32_t h) = 0;
+
+ virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) = 0;
+
+ virtual status_t setDefaultBufferFormat(PixelFormat defaultFormat) = 0;
+
+ virtual status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace) = 0;
+
+ virtual status_t setConsumerUsageBits(uint64_t usage) = 0;
+
+ virtual status_t setConsumerIsProtected(bool isProtected) = 0;
+
+ virtual status_t discardFreeBuffers() = 0;
+};
+
+} // namespace android
\ No newline at end of file
diff --git a/libs/hostgraphics/gui/IGraphicBufferProducer.h b/libs/hostgraphics/gui/IGraphicBufferProducer.h
index 0042213..a1efd0b 100644
--- a/libs/hostgraphics/gui/IGraphicBufferProducer.h
+++ b/libs/hostgraphics/gui/IGraphicBufferProducer.h
@@ -19,6 +19,8 @@
#include <utils/RefBase.h>
+#include <ui/GraphicBuffer.h>
+
namespace android {
class IGraphicBufferProducer : virtual public RefBase {
diff --git a/libs/hostgraphics/ui/Fence.h b/libs/hostgraphics/ui/Fence.h
new file mode 100644
index 0000000..04d535c
--- /dev/null
+++ b/libs/hostgraphics/ui/Fence.h
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_FENCE_H
+#define ANDROID_FENCE_H
+
+#include <utils/String8.h>
+#include <utils/RefBase.h>
+
+typedef int64_t nsecs_t;
+
+namespace android {
+
+class Fence : public LightRefBase<Fence> {
+public:
+ Fence() { }
+ Fence(int) { }
+ static const sp<Fence> NO_FENCE;
+ static constexpr nsecs_t SIGNAL_TIME_PENDING = INT64_MAX;
+ static constexpr nsecs_t SIGNAL_TIME_INVALID = -1;
+ static sp<Fence> merge(const char* name, const sp<Fence>& f1, const sp<Fence>& f2) {
+ return NO_FENCE;
+ }
+
+ static sp<Fence> merge(const String8& name, const sp<Fence>& f1, const sp<Fence>& f2) {
+ return NO_FENCE;
+ }
+
+ enum class Status {
+ Invalid, // Fence is invalid
+ Unsignaled, // Fence is valid but has not yet signaled
+ Signaled, // Fence is valid and has signaled
+ };
+
+ status_t wait(int timeout) { return OK; }
+
+ status_t waitForever(const char* logname) { return OK; }
+
+ int dup() const { return 0; }
+
+ inline Status getStatus() {
+ // The sync_wait call underlying wait() has been measured to be
+ // significantly faster than the sync_fence_info call underlying
+ // getSignalTime(), which might otherwise appear to be the more obvious
+ // way to check whether a fence has signaled.
+ switch (wait(0)) {
+ case NO_ERROR:
+ return Status::Signaled;
+ case -ETIME:
+ return Status::Unsignaled;
+ default:
+ return Status::Invalid;
+ }
+ }
+};
+
+} // namespace android
+
+#endif // ANDROID_FENCE_H
diff --git a/libs/hostgraphics/ui/GraphicBuffer.h b/libs/hostgraphics/ui/GraphicBuffer.h
new file mode 100644
index 0000000..ac88e44
--- /dev/null
+++ b/libs/hostgraphics/ui/GraphicBuffer.h
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_GRAPHIC_BUFFER_H
+#define ANDROID_GRAPHIC_BUFFER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <vector>
+
+#include <ui/PixelFormat.h>
+#include <ui/Rect.h>
+
+#include <utils/RefBase.h>
+
+namespace android {
+
+class GraphicBuffer : virtual public RefBase {
+public:
+ GraphicBuffer(uint32_t w, uint32_t h):width(w),height(h) {
+ data.resize(w*h);
+ }
+ uint32_t getWidth() const { return static_cast<uint32_t>(width); }
+ uint32_t getHeight() const { return static_cast<uint32_t>(height); }
+ uint32_t getStride() const { return static_cast<uint32_t>(width); }
+ uint64_t getUsage() const { return 0; }
+ PixelFormat getPixelFormat() const { return PIXEL_FORMAT_RGBA_8888; }
+ //uint32_t getLayerCount() const { return static_cast<uint32_t>(layerCount); }
+ Rect getBounds() const { return Rect(width, height); }
+
+ status_t lockAsyncYCbCr(uint32_t inUsage, const Rect& rect,
+ android_ycbcr *ycbcr, int fenceFd) { return OK; }
+
+ status_t lockAsync(uint32_t inUsage, const Rect& rect, void** vaddr, int fenceFd,
+ int32_t* outBytesPerPixel = nullptr, int32_t* outBytesPerStride = nullptr) {
+ *vaddr = data.data();
+ return OK;
+ }
+
+ status_t unlockAsync(int *fenceFd) { return OK; }
+
+private:
+ uint32_t width;
+ uint32_t height;
+ std::vector<uint32_t> data;
+};
+
+}; // namespace android
+
+#endif // ANDROID_GRAPHIC_BUFFER_H
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 5100165..35abc57 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -138,14 +138,14 @@
err = mCreateInstance(&instance_create, nullptr, &mInstance);
LOG_ALWAYS_FATAL_IF(err < 0);
+ GET_INST_PROC(CreateDevice);
GET_INST_PROC(DestroyInstance);
+ GET_INST_PROC(EnumerateDeviceExtensionProperties);
GET_INST_PROC(EnumeratePhysicalDevices);
- GET_INST_PROC(GetPhysicalDeviceProperties);
- GET_INST_PROC(GetPhysicalDeviceQueueFamilyProperties);
GET_INST_PROC(GetPhysicalDeviceFeatures2);
GET_INST_PROC(GetPhysicalDeviceImageFormatProperties2);
- GET_INST_PROC(CreateDevice);
- GET_INST_PROC(EnumerateDeviceExtensionProperties);
+ GET_INST_PROC(GetPhysicalDeviceProperties);
+ GET_INST_PROC(GetPhysicalDeviceQueueFamilyProperties);
uint32_t gpuCount;
LOG_ALWAYS_FATAL_IF(mEnumeratePhysicalDevices(mInstance, &gpuCount, nullptr));
@@ -312,29 +312,27 @@
LOG_ALWAYS_FATAL_IF(mCreateDevice(mPhysicalDevice, &deviceInfo, nullptr, &mDevice));
- GET_DEV_PROC(GetDeviceQueue);
- GET_DEV_PROC(DeviceWaitIdle);
- GET_DEV_PROC(DestroyDevice);
- GET_DEV_PROC(CreateCommandPool);
- GET_DEV_PROC(DestroyCommandPool);
GET_DEV_PROC(AllocateCommandBuffers);
- GET_DEV_PROC(FreeCommandBuffers);
- GET_DEV_PROC(ResetCommandBuffer);
GET_DEV_PROC(BeginCommandBuffer);
- GET_DEV_PROC(EndCommandBuffer);
GET_DEV_PROC(CmdPipelineBarrier);
+ GET_DEV_PROC(CreateCommandPool);
+ GET_DEV_PROC(CreateFence);
+ GET_DEV_PROC(CreateSemaphore);
+ GET_DEV_PROC(DestroyCommandPool);
+ GET_DEV_PROC(DestroyDevice);
+ GET_DEV_PROC(DestroyFence);
+ GET_DEV_PROC(DestroySemaphore);
+ GET_DEV_PROC(DeviceWaitIdle);
+ GET_DEV_PROC(EndCommandBuffer);
+ GET_DEV_PROC(FreeCommandBuffers);
GET_DEV_PROC(GetDeviceQueue);
+ GET_DEV_PROC(GetSemaphoreFdKHR);
+ GET_DEV_PROC(ImportSemaphoreFdKHR);
GET_DEV_PROC(QueueSubmit);
GET_DEV_PROC(QueueWaitIdle);
- GET_DEV_PROC(DeviceWaitIdle);
- GET_DEV_PROC(CreateSemaphore);
- GET_DEV_PROC(DestroySemaphore);
- GET_DEV_PROC(ImportSemaphoreFdKHR);
- GET_DEV_PROC(GetSemaphoreFdKHR);
- GET_DEV_PROC(CreateFence);
- GET_DEV_PROC(DestroyFence);
- GET_DEV_PROC(WaitForFences);
+ GET_DEV_PROC(ResetCommandBuffer);
GET_DEV_PROC(ResetFences);
+ GET_DEV_PROC(WaitForFences);
}
void VulkanManager::initialize() {
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index 89d3cc4..16f2917 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -20,6 +20,7 @@
],
shared_libs: [
+ "libbinder",
"libcutils",
"liblog",
"libutils",
diff --git a/libs/input/SpriteController.cpp b/libs/input/SpriteController.cpp
index c1868d3..fd386e9 100644
--- a/libs/input/SpriteController.cpp
+++ b/libs/input/SpriteController.cpp
@@ -245,7 +245,8 @@
if (update.state.surfaceControl != NULL && (becomingVisible || becomingHidden
|| (wantSurfaceVisibleAndDrawn && (update.state.dirty & (DIRTY_ALPHA
| DIRTY_POSITION | DIRTY_TRANSFORMATION_MATRIX | DIRTY_LAYER
- | DIRTY_VISIBILITY | DIRTY_HOTSPOT | DIRTY_DISPLAY_ID))))) {
+ | DIRTY_VISIBILITY | DIRTY_HOTSPOT | DIRTY_DISPLAY_ID
+ | DIRTY_ICON_STYLE))))) {
needApplyTransaction = true;
if (wantSurfaceVisibleAndDrawn
@@ -274,6 +275,21 @@
update.state.transformationMatrix.dtdy);
}
+ if (wantSurfaceVisibleAndDrawn
+ && (becomingVisible
+ || (update.state.dirty & (DIRTY_HOTSPOT | DIRTY_ICON_STYLE)))) {
+ Parcel p;
+ p.writeInt32(update.state.icon.style);
+ p.writeFloat(update.state.icon.hotSpotX);
+ p.writeFloat(update.state.icon.hotSpotY);
+
+ // Pass cursor metadata in the sprite surface so that when Android is running as a
+ // client OS (e.g. ARC++) the host OS can get the requested cursor metadata and
+ // update mouse cursor in the host OS.
+ t.setMetadata(
+ update.state.surfaceControl, METADATA_MOUSE_CURSOR, p);
+ }
+
int32_t surfaceLayer = mOverlayLayer + update.state.layer;
if (wantSurfaceVisibleAndDrawn
&& (becomingVisible || (update.state.dirty & DIRTY_LAYER))) {
@@ -397,9 +413,14 @@
} else {
dirty = DIRTY_BITMAP;
}
+
+ if (mLocked.state.icon.style != icon.style) {
+ mLocked.state.icon.style = icon.style;
+ dirty |= DIRTY_ICON_STYLE;
+ }
} else if (mLocked.state.icon.isValid()) {
mLocked.state.icon.bitmap.reset();
- dirty = DIRTY_BITMAP | DIRTY_HOTSPOT;
+ dirty = DIRTY_BITMAP | DIRTY_HOTSPOT | DIRTY_ICON_STYLE;
} else {
return; // setting to invalid icon and already invalid so nothing to do
}
diff --git a/libs/input/SpriteController.h b/libs/input/SpriteController.h
index 5b216f5..79a904f 100644
--- a/libs/input/SpriteController.h
+++ b/libs/input/SpriteController.h
@@ -55,11 +55,12 @@
* Icon that a sprite displays, including its hotspot.
*/
struct SpriteIcon {
- inline SpriteIcon() : hotSpotX(0), hotSpotY(0) { }
- inline SpriteIcon(const SkBitmap& bitmap, float hotSpotX, float hotSpotY) :
- bitmap(bitmap), hotSpotX(hotSpotX), hotSpotY(hotSpotY) { }
+ inline SpriteIcon() : style(0), hotSpotX(0), hotSpotY(0) { }
+ inline SpriteIcon(const SkBitmap& bitmap, int32_t style, float hotSpotX, float hotSpotY) :
+ bitmap(bitmap), style(style), hotSpotX(hotSpotX), hotSpotY(hotSpotY) { }
SkBitmap bitmap;
+ int32_t style;
float hotSpotX;
float hotSpotY;
@@ -69,11 +70,12 @@
bitmap.readPixels(bitmapCopy.info(), bitmapCopy.getPixels(), bitmapCopy.rowBytes(),
0, 0);
}
- return SpriteIcon(bitmapCopy, hotSpotX, hotSpotY);
+ return SpriteIcon(bitmapCopy, style, hotSpotX, hotSpotY);
}
inline void reset() {
bitmap.reset();
+ style = 0;
hotSpotX = 0;
hotSpotY = 0;
}
@@ -149,15 +151,15 @@
SpriteController(const sp<Looper>& looper, int32_t overlayLayer);
/* Creates a new sprite, initially invisible. */
- sp<Sprite> createSprite();
+ virtual sp<Sprite> createSprite();
/* Opens or closes a transaction to perform a batch of sprite updates as part of
* a single operation such as setPosition and setAlpha. It is not necessary to
* open a transaction when updating a single property.
* Calls to openTransaction() nest and must be matched by an equal number
* of calls to closeTransaction(). */
- void openTransaction();
- void closeTransaction();
+ virtual void openTransaction();
+ virtual void closeTransaction();
private:
enum {
@@ -174,6 +176,7 @@
DIRTY_VISIBILITY = 1 << 5,
DIRTY_HOTSPOT = 1 << 6,
DIRTY_DISPLAY_ID = 1 << 7,
+ DIRTY_ICON_STYLE = 1 << 8,
};
/* Describes the state of a sprite.
diff --git a/libs/input/TEST_MAPPING b/libs/input/TEST_MAPPING
new file mode 100644
index 0000000..fe74c62
--- /dev/null
+++ b/libs/input/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "libinputservice_test"
+ }
+ ]
+}
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
new file mode 100644
index 0000000..e83b2a7
--- /dev/null
+++ b/libs/input/tests/Android.bp
@@ -0,0 +1,45 @@
+// 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.
+
+cc_test {
+ name: "libinputservice_test",
+ srcs: [
+ "PointerController_test.cpp",
+ ],
+ shared_libs: [
+ "libinputservice",
+ "libgui",
+ "libhwui",
+ "libutils",
+ ],
+ static_libs: [
+ "libgmock",
+ "libgtest",
+ ],
+ header_libs: [
+ "libbase_headers",
+ "libinputflinger_headers",
+ ],
+ include_dirs: [
+ "frameworks/base/libs",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+ test_suites: [
+ "general-tests",
+ ],
+}
diff --git a/libs/input/tests/PointerController_test.cpp b/libs/input/tests/PointerController_test.cpp
new file mode 100644
index 0000000..92efb4e
--- /dev/null
+++ b/libs/input/tests/PointerController_test.cpp
@@ -0,0 +1,215 @@
+/*
+ * 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.
+ */
+
+#include "mocks/MockSprite.h"
+#include "mocks/MockSpriteController.h"
+
+#include <input/PointerController.h>
+#include <input/SpriteController.h>
+
+#include <atomic>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <thread>
+
+namespace android {
+
+enum TestCursorType {
+ CURSOR_TYPE_DEFAULT = 0,
+ CURSOR_TYPE_HOVER,
+ CURSOR_TYPE_TOUCH,
+ CURSOR_TYPE_ANCHOR,
+ CURSOR_TYPE_ADDITIONAL_1,
+ CURSOR_TYPE_ADDITIONAL_2,
+ CURSOR_TYPE_CUSTOM = -1,
+};
+
+using ::testing::AllOf;
+using ::testing::Field;
+using ::testing::NiceMock;
+using ::testing::Mock;
+using ::testing::Return;
+using ::testing::Test;
+
+std::pair<float, float> getHotSpotCoordinatesForType(int32_t type) {
+ return std::make_pair(type * 10, type * 10 + 5);
+}
+
+class MockPointerControllerPolicyInterface : public PointerControllerPolicyInterface {
+public:
+ virtual void loadPointerIcon(SpriteIcon* icon, int32_t displayId) override;
+ virtual void loadPointerResources(PointerResources* outResources, int32_t displayId) override;
+ virtual void loadAdditionalMouseResources(std::map<int32_t, SpriteIcon>* outResources,
+ std::map<int32_t, PointerAnimation>* outAnimationResources, int32_t displayId) override;
+ virtual int32_t getDefaultPointerIconId() override;
+ virtual int32_t getCustomPointerIconId() override;
+
+private:
+ void loadPointerIconForType(SpriteIcon* icon, int32_t cursorType);
+};
+
+void MockPointerControllerPolicyInterface::loadPointerIcon(SpriteIcon* icon, int32_t) {
+ loadPointerIconForType(icon, CURSOR_TYPE_DEFAULT);
+}
+
+void MockPointerControllerPolicyInterface::loadPointerResources(PointerResources* outResources,
+ int32_t) {
+ loadPointerIconForType(&outResources->spotHover, CURSOR_TYPE_HOVER);
+ loadPointerIconForType(&outResources->spotTouch, CURSOR_TYPE_TOUCH);
+ loadPointerIconForType(&outResources->spotAnchor, CURSOR_TYPE_ANCHOR);
+}
+
+void MockPointerControllerPolicyInterface::loadAdditionalMouseResources(
+ std::map<int32_t, SpriteIcon>* outResources,
+ std::map<int32_t, PointerAnimation>* outAnimationResources,
+ int32_t) {
+ SpriteIcon icon;
+ PointerAnimation anim;
+
+ for (int32_t cursorType : {CURSOR_TYPE_ADDITIONAL_1, CURSOR_TYPE_ADDITIONAL_2}) {
+ loadPointerIconForType(&icon, cursorType);
+ anim.animationFrames.push_back(icon);
+ anim.durationPerFrame = 10;
+ (*outResources)[cursorType] = icon;
+ (*outAnimationResources)[cursorType] = anim;
+ }
+}
+
+int32_t MockPointerControllerPolicyInterface::getDefaultPointerIconId() {
+ return CURSOR_TYPE_DEFAULT;
+}
+
+int32_t MockPointerControllerPolicyInterface::getCustomPointerIconId() {
+ return CURSOR_TYPE_CUSTOM;
+}
+
+void MockPointerControllerPolicyInterface::loadPointerIconForType(SpriteIcon* icon, int32_t type) {
+ icon->style = type;
+ std::pair<float, float> hotSpot = getHotSpotCoordinatesForType(type);
+ icon->hotSpotX = hotSpot.first;
+ icon->hotSpotY = hotSpot.second;
+}
+
+class PointerControllerTest : public Test {
+protected:
+ PointerControllerTest();
+ ~PointerControllerTest();
+
+ sp<MockSprite> mPointerSprite;
+ sp<MockPointerControllerPolicyInterface> mPolicy;
+ sp<MockSpriteController> mSpriteController;
+ sp<PointerController> mPointerController;
+
+private:
+ void loopThread();
+
+ std::atomic<bool> mRunning = true;
+ class MyLooper : public Looper {
+ public:
+ MyLooper() : Looper(false) {}
+ ~MyLooper() = default;
+ };
+ sp<MyLooper> mLooper;
+ std::thread mThread;
+};
+
+PointerControllerTest::PointerControllerTest() : mPointerSprite(new NiceMock<MockSprite>),
+ mLooper(new MyLooper), mThread(&PointerControllerTest::loopThread, this) {
+
+ mSpriteController = new NiceMock<MockSpriteController>(mLooper);
+ mPolicy = new MockPointerControllerPolicyInterface();
+
+ EXPECT_CALL(*mSpriteController, createSprite())
+ .WillOnce(Return(mPointerSprite));
+
+ mPointerController = new PointerController(mPolicy, mLooper, mSpriteController);
+
+ DisplayViewport viewport;
+ viewport.displayId = ADISPLAY_ID_DEFAULT;
+ viewport.logicalRight = 1600;
+ viewport.logicalBottom = 1200;
+ viewport.physicalRight = 800;
+ viewport.physicalBottom = 600;
+ viewport.deviceWidth = 400;
+ viewport.deviceHeight = 300;
+ mPointerController->setDisplayViewport(viewport);
+}
+
+PointerControllerTest::~PointerControllerTest() {
+ mRunning.store(false, std::memory_order_relaxed);
+ mThread.join();
+}
+
+void PointerControllerTest::loopThread() {
+ Looper::setForThread(mLooper);
+
+ while (mRunning.load(std::memory_order_relaxed)) {
+ mLooper->pollOnce(100);
+ }
+}
+
+TEST_F(PointerControllerTest, useDefaultCursorTypeByDefault) {
+ mPointerController->unfade(PointerController::TRANSITION_IMMEDIATE);
+
+ std::pair<float, float> hotspot = getHotSpotCoordinatesForType(CURSOR_TYPE_DEFAULT);
+ EXPECT_CALL(*mPointerSprite, setVisible(true));
+ EXPECT_CALL(*mPointerSprite, setAlpha(1.0f));
+ EXPECT_CALL(*mPointerSprite, setIcon(
+ AllOf(
+ Field(&SpriteIcon::style, CURSOR_TYPE_DEFAULT),
+ Field(&SpriteIcon::hotSpotX, hotspot.first),
+ Field(&SpriteIcon::hotSpotY, hotspot.second))));
+ mPointerController->reloadPointerResources();
+}
+
+TEST_F(PointerControllerTest, updatePointerIcon) {
+ mPointerController->unfade(PointerController::TRANSITION_IMMEDIATE);
+
+ int32_t type = CURSOR_TYPE_ADDITIONAL_1;
+ std::pair<float, float> hotspot = getHotSpotCoordinatesForType(type);
+ EXPECT_CALL(*mPointerSprite, setVisible(true));
+ EXPECT_CALL(*mPointerSprite, setAlpha(1.0f));
+ EXPECT_CALL(*mPointerSprite, setIcon(
+ AllOf(
+ Field(&SpriteIcon::style, type),
+ Field(&SpriteIcon::hotSpotX, hotspot.first),
+ Field(&SpriteIcon::hotSpotY, hotspot.second))));
+ mPointerController->updatePointerIcon(type);
+}
+
+TEST_F(PointerControllerTest, setCustomPointerIcon) {
+ mPointerController->unfade(PointerController::TRANSITION_IMMEDIATE);
+
+ int32_t style = CURSOR_TYPE_CUSTOM;
+ float hotSpotX = 15;
+ float hotSpotY = 20;
+
+ SpriteIcon icon;
+ icon.style = style;
+ icon.hotSpotX = hotSpotX;
+ icon.hotSpotY = hotSpotY;
+
+ EXPECT_CALL(*mPointerSprite, setVisible(true));
+ EXPECT_CALL(*mPointerSprite, setAlpha(1.0f));
+ EXPECT_CALL(*mPointerSprite, setIcon(
+ AllOf(
+ Field(&SpriteIcon::style, style),
+ Field(&SpriteIcon::hotSpotX, hotSpotX),
+ Field(&SpriteIcon::hotSpotY, hotSpotY))));
+ mPointerController->setCustomPointerIcon(icon);
+}
+
+} // namespace android
diff --git a/libs/input/tests/mocks/MockSprite.h b/libs/input/tests/mocks/MockSprite.h
new file mode 100644
index 0000000..013b79c
--- /dev/null
+++ b/libs/input/tests/mocks/MockSprite.h
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+#ifndef _MOCK_SPRITE_H
+#define _MOCK_SPRITE_H
+
+#include <input/SpriteController.h>
+
+#include <gmock/gmock.h>
+
+namespace android {
+
+class MockSprite : public Sprite {
+public:
+ virtual ~MockSprite() = default;
+
+ MOCK_METHOD(void, setIcon, (const SpriteIcon& icon), (override));
+ MOCK_METHOD(void, setVisible, (bool), (override));
+ MOCK_METHOD(void, setPosition, (float, float), (override));
+ MOCK_METHOD(void, setLayer, (int32_t), (override));
+ MOCK_METHOD(void, setAlpha, (float), (override));
+ MOCK_METHOD(void, setTransformationMatrix, (const SpriteTransformationMatrix&), (override));
+ MOCK_METHOD(void, setDisplayId, (int32_t), (override));
+};
+
+} // namespace android
+
+#endif // _MOCK_SPRITE_H
diff --git a/libs/input/tests/mocks/MockSpriteController.h b/libs/input/tests/mocks/MockSpriteController.h
new file mode 100644
index 0000000..a034f66
--- /dev/null
+++ b/libs/input/tests/mocks/MockSpriteController.h
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+#ifndef _MOCK_SPRITE_CONTROLLER_H
+#define _MOCK_SPRITE_CONTROLLER_H
+
+#include "MockSprite.h"
+
+#include <input/SpriteController.h>
+
+namespace android {
+
+class MockSpriteController : public SpriteController {
+
+public:
+ MockSpriteController(sp<Looper> looper) : SpriteController(looper, 0) {}
+ ~MockSpriteController() {}
+
+ MOCK_METHOD(sp<Sprite>, createSprite, (), (override));
+ MOCK_METHOD(void, openTransaction, (), (override));
+ MOCK_METHOD(void, closeTransaction, (), (override));
+};
+
+} // namespace android
+
+#endif // _MOCK_SPRITE_CONTROLLER_H
diff --git a/location/lib/Android.bp b/location/lib/Android.bp
index ab01ddb..db63889 100644
--- a/location/lib/Android.bp
+++ b/location/lib/Android.bp
@@ -22,6 +22,8 @@
],
api_packages: ["com.android.location.provider"],
srcs_lib: "framework-minus-apex",
- srcs_lib_whitelist_dirs: ["location/java"],
- srcs_lib_whitelist_pkgs: ["com.android.internal.location"],
+ // TODO(b/70046217): remove core/java and android below. It was added to provide definitions for
+ // types like android.os.Bundle
+ srcs_lib_whitelist_dirs: ["core/java", "location/java"],
+ srcs_lib_whitelist_pkgs: ["android", "com.android.internal.location"],
}
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 148ffaf..55583d5 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -37,6 +37,7 @@
import libcore.io.Streams;
import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.DataInput;
import java.io.DataInputStream;
@@ -1866,14 +1867,17 @@
FileInputStream in = null;
FileOutputStream out = null;
+ File originalFile = null;
+ if (mFilename != null) {
+ originalFile = new File(mFilename);
+ }
File tempFile = null;
try {
// Move the original file to temporary file.
if (mFilename != null) {
tempFile = new File(mFilename + ".tmp");
- File originalFile = new File(mFilename);
if (!originalFile.renameTo(tempFile)) {
- throw new IOException("Could'nt rename to " + tempFile.getAbsolutePath());
+ throw new IOException("Couldn't rename to " + tempFile.getAbsolutePath());
}
} else if (mSeekableFileDescriptor != null) {
tempFile = File.createTempFile("temp", "jpg");
@@ -1882,8 +1886,8 @@
out = new FileOutputStream(tempFile);
Streams.copy(in, out);
}
- } catch (ErrnoException e) {
- throw e.rethrowAsIOException();
+ } catch (Exception e) {
+ throw new IOException("Failed to copy original file to temp file", e);
} finally {
IoUtils.closeQuietly(in);
IoUtils.closeQuietly(out);
@@ -1900,9 +1904,18 @@
Os.lseek(mSeekableFileDescriptor, 0, OsConstants.SEEK_SET);
out = new FileOutputStream(mSeekableFileDescriptor);
}
- saveJpegAttributes(in, out);
- } catch (ErrnoException e) {
- throw e.rethrowAsIOException();
+ try (BufferedInputStream bufferedIn = new BufferedInputStream(in);
+ BufferedOutputStream bufferedOut = new BufferedOutputStream(out)) {
+ saveJpegAttributes(bufferedIn, bufferedOut);
+ }
+ } catch (Exception e) {
+ if (mFilename != null) {
+ if (!tempFile.renameTo(originalFile)) {
+ throw new IOException("Couldn't restore original file: "
+ + originalFile.getAbsolutePath());
+ }
+ }
+ throw new IOException("Failed to save new file", e);
} finally {
IoUtils.closeQuietly(in);
IoUtils.closeQuietly(out);
diff --git a/media/java/android/media/Metadata.java b/media/java/android/media/Metadata.java
index 792a2ba..be0d966 100644
--- a/media/java/android/media/Metadata.java
+++ b/media/java/android/media/Metadata.java
@@ -272,6 +272,15 @@
@UnsupportedAppUsage
public Metadata() { }
+ // Have to declare protected for finalize() since it is protected
+ // in the base class Object.
+ @Override
+ protected void finalize() throws Throwable {
+ if (mParcel != null) {
+ mParcel.recycle();
+ }
+ }
+
/**
* Go over all the records, collecting metadata keys and records'
* type field offset in the Parcel. These are stored in
@@ -418,6 +427,10 @@
parcel.setDataPosition(pin);
return false;
}
+
+ if (mParcel != null) {
+ mParcel.recycle();
+ }
mParcel = parcel;
return true;
}
diff --git a/packages/CarSystemUI/AndroidManifest.xml b/packages/CarSystemUI/AndroidManifest.xml
index 195d4fe..261b9f5 100644
--- a/packages/CarSystemUI/AndroidManifest.xml
+++ b/packages/CarSystemUI/AndroidManifest.xml
@@ -21,4 +21,8 @@
coreApp="true">
<!-- This permission is required to monitor car power state. -->
<uses-permission android:name="android.car.permission.CAR_POWER" />
+ <!-- This permission is required to get the trusted device list of a user. -->
+ <uses-permission android:name="android.car.permission.CAR_ENROLL_TRUST"/>
+ <!-- This permission is required to get bluetooth broadcast. -->
+ <uses-permission android:name="android.permission.BLUETOOTH" />
</manifest>
diff --git a/packages/CarSystemUI/res/drawable/unlock_dialog_background.xml b/packages/CarSystemUI/res/drawable/unlock_dialog_background.xml
new file mode 100644
index 0000000..bec6ba7
--- /dev/null
+++ b/packages/CarSystemUI/res/drawable/unlock_dialog_background.xml
@@ -0,0 +1,26 @@
+<?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
+ -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <solid android:color="@color/unlock_dialog_background_color"/>
+ <padding
+ android:bottom="@*android:dimen/car_padding_2"
+ android:left="@*android:dimen/car_padding_2"
+ android:right="@*android:dimen/car_padding_2"
+ android:top="@*android:dimen/car_padding_2"/>
+ <corners
+ android:radius="@dimen/unlock_dialog_radius"/>
+</shape>
\ No newline at end of file
diff --git a/packages/CarSystemUI/res/layout/trust_agent_unlock_dialog.xml b/packages/CarSystemUI/res/layout/trust_agent_unlock_dialog.xml
new file mode 100644
index 0000000..2d9901c
--- /dev/null
+++ b/packages/CarSystemUI/res/layout/trust_agent_unlock_dialog.xml
@@ -0,0 +1,72 @@
+<?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
+ -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center">
+
+ <LinearLayout
+ android:layout_width="@dimen/unlock_dialog_width"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:layout_gravity="center"
+ android:orientation="vertical"
+ android:background="@drawable/unlock_dialog_background"
+ android:padding="@*android:dimen/car_padding_2">
+ <FrameLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+ <ProgressBar
+ android:layout_gravity="center"
+ android:layout_width="@dimen/unlock_dialog_progress_bar_size"
+ android:layout_height="@dimen/unlock_dialog_progress_bar_size" />
+ <ImageView
+ android:id="@+id/avatar"
+ android:layout_gravity="center"
+ android:layout_width="@dimen/unlock_dialog_avatar_size"
+ android:layout_height="@dimen/unlock_dialog_avatar_size"
+ android:scaleType="fitCenter"/>
+ </FrameLayout>
+
+ <TextView
+ android:id="@+id/user_name"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:text="@string/unlock_dialog_default_user_name"
+ android:textSize="@*android:dimen/car_body1_size"
+ android:textColor="@android:color/white"/>
+
+ <TextView
+ android:id="@+id/unlocking_text"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_marginTop="@*android:dimen/car_padding_1"
+ android:text="@string/unlock_dialog_message_default"
+ android:textSize="@*android:dimen/car_body4_size"
+ android:textColor="@color/unlock_dialog_message_text_default"/>
+
+ <Button
+ android:id="@+id/enter_pin_button"
+ android:layout_marginTop="@*android:dimen/car_padding_1"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:text="@string/unlock_dialog_button_text_pin"
+ style="@style/UnlockDialogButton"/>
+ </LinearLayout>
+</FrameLayout>
\ No newline at end of file
diff --git a/packages/CarSystemUI/res/values/colors_car.xml b/packages/CarSystemUI/res/values/colors_car.xml
index 69ab3f3..0a3f7aa 100644
--- a/packages/CarSystemUI/res/values/colors_car.xml
+++ b/packages/CarSystemUI/res/values/colors_car.xml
@@ -26,4 +26,9 @@
<color name="car_user_switcher_add_user_background_color">@*android:color/car_dark_blue_grey_600</color>
<color name="car_user_switcher_add_user_add_sign_color">@*android:color/car_body1_light</color>
+ <!-- colors for unlock dialog -->
+ <color name="unlock_dialog_background_color">#ff282a2d</color>
+ <color name="unlock_dialog_message_text_default">@*android:color/car_grey_400</color>
+ <color name="unlock_dialog_enter_pin_text_color">#ff66b5ff</color>
+
</resources>
diff --git a/packages/CarSystemUI/res/values/dimens_car.xml b/packages/CarSystemUI/res/values/dimens_car.xml
index 42a7649..9cb09c9 100644
--- a/packages/CarSystemUI/res/values/dimens_car.xml
+++ b/packages/CarSystemUI/res/values/dimens_car.xml
@@ -43,4 +43,10 @@
<!-- This must be the negative of car_user_switcher_container_height for the animation. -->
<dimen name="car_user_switcher_container_anim_height">-420dp</dimen>
+ <!-- dimensions for the unlock dialog -->
+ <dimen name="unlock_dialog_width">500dp</dimen>
+ <dimen name="unlock_dialog_radius">16dp</dimen>
+ <dimen name="unlock_dialog_avatar_size">100dp</dimen>
+ <dimen name="unlock_dialog_progress_bar_size">140dp</dimen>
+
</resources>
diff --git a/packages/CarSystemUI/res/values/integers_car.xml b/packages/CarSystemUI/res/values/integers_car.xml
index be2cb0d..862ba75 100644
--- a/packages/CarSystemUI/res/values/integers_car.xml
+++ b/packages/CarSystemUI/res/values/integers_car.xml
@@ -31,5 +31,7 @@
<!--Percentage of the screen height, from the bottom, that a notification panel being peeked
at will result in remaining closed the panel if released-->
<integer name="notification_settle_close_percentage">80</integer>
+ <!-- The delay before the unlock dialog pops up -->
+ <integer name="unlock_dialog_delay_ms">3000</integer>
</resources>
diff --git a/packages/CarSystemUI/res/values/strings_car.xml b/packages/CarSystemUI/res/values/strings_car.xml
index 83e91c5..717692e 100644
--- a/packages/CarSystemUI/res/values/strings_car.xml
+++ b/packages/CarSystemUI/res/values/strings_car.xml
@@ -29,4 +29,19 @@
<string name="user_add_user_message_setup">When you add a new user, that person needs to set up their space.</string>
<!-- Message to inform user that the newly created user will have permissions to update apps for all other users. [CHAR LIMIT=100] -->
<string name="user_add_user_message_update">Any user can update apps for all other users.</string>
+ <!-- Default messages displayed on the unlock dialog before unlock advertising started. [CHAR LIMIT=30]-->
+ <string name="unlock_dialog_message_default">Waiting\u2026</string>
+ <!-- Message to inform user that the IHU is looking for trusted device. [CHAR LIMIT=30] -->
+ <string name="unlock_dialog_message_start">Looking for trusted device\u2026</string>
+
+ <!-- Cancel Button text for user who has PIN as security lock. [CHAR LIMIT=30] -->
+ <string name="unlock_dialog_button_text_pin">Enter PIN instead</string>
+ <!-- Cancel Button text for user who has Pattern as security lock. [CHAR LIMIT=30] -->
+ <string name="unlock_dialog_button_text_pattern">Enter Pattern instead</string>
+ <!-- Cancel Button text for user who has Password as security lock. [CHAR LIMIT=30] -->
+ <string name="unlock_dialog_button_text_password">Enter Password instead</string>
+ <!-- Default user name shows on unlock dialog -->
+ <string name="unlock_dialog_default_user_name">Default Name</string>
+ <!-- Default title for unlock dialog -->
+ <string name="unlock_dialog_title">Unlock Dialogue</string>
</resources>
diff --git a/packages/CarSystemUI/res/values/styles.xml b/packages/CarSystemUI/res/values/styles.xml
index 371bebd..a9423bf 100644
--- a/packages/CarSystemUI/res/values/styles.xml
+++ b/packages/CarSystemUI/res/values/styles.xml
@@ -46,4 +46,12 @@
<item name="android:layout_width">96dp</item>
<item name="android:background">@drawable/nav_button_background</item>
</style>
+
+ <style name="UnlockDialogButton">
+ <item name="android:background">?android:attr/selectableItemBackground</item>
+ <item name="android:textAlignment">center</item>
+ <item name="android:textColor">@color/unlock_dialog_enter_pin_text_color</item>
+ <item name="android:paddingHorizontal">16dp</item>
+ <item name="android:textAllCaps">false</item>
+ </style>
</resources>
\ No newline at end of file
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 b1f9797..e95103b 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -26,12 +26,16 @@
import android.car.drivingstate.CarDrivingStateEvent;
import android.car.drivingstate.CarUxRestrictionsManager;
import android.car.hardware.power.CarPowerManager.CarPowerStateListener;
+import android.car.trust.CarTrustAgentEnrollmentManager;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.inputmethodservice.InputMethodService;
+import android.os.IBinder;
import android.util.Log;
+import android.view.Display;
import android.view.GestureDetector;
import android.view.Gravity;
import android.view.MotionEvent;
@@ -86,8 +90,7 @@
/**
* A status bar (and navigation bar) tailored for the automotive use case.
*/
-public class CarStatusBar extends StatusBar implements
- CarBatteryController.BatteryViewHandler {
+public class CarStatusBar extends StatusBar implements CarBatteryController.BatteryViewHandler {
private static final String TAG = "CarStatusBar";
// used to calculate how fast to open or close the window
private static final float DEFAULT_FLING_VELOCITY = 0;
@@ -168,6 +171,9 @@
private boolean mIsSwipingVerticallyToClose;
// Whether heads-up notifications should be shown when shade is open.
private boolean mEnableHeadsUpNotificationWhenNotificationShadeOpen;
+ // If the nav bar should be hidden when the soft keyboard is visible.
+ private boolean mHideNavBarForKeyboard;
+ private boolean mBottomNavBarVisible;
private final CarPowerStateListener mCarPowerStateListener =
(int state) -> {
@@ -189,6 +195,12 @@
// builds the nav bar
mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
mDeviceIsProvisioned = mDeviceProvisionedController.isDeviceProvisioned();
+
+ // Keyboard related setup, before nav bars are created.
+ mHideNavBarForKeyboard = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_automotiveHideNavBarForKeyboard);
+ mBottomNavBarVisible = false;
+
super.start();
mTaskStackListener = new TaskStackListenerImpl();
mActivityManagerWrapper = ActivityManagerWrapper.getInstance();
@@ -719,6 +731,13 @@
buildNavBarContent();
attachNavBarWindows();
+ // Try setting up the initial state of the nav bar if applicable.
+ if (result != null) {
+ setImeWindowStatus(Display.DEFAULT_DISPLAY, result.mImeToken,
+ result.mImeWindowVis, result.mImeBackDisposition,
+ result.mShowImeSwitcher);
+ }
+
// There has been a car customized nav bar on the default display, so just create nav bars
// on external displays.
mNavigationBarController.createNavigationBars(false /* includeDefaultDisplay */, result);
@@ -757,22 +776,33 @@
}
- private void attachNavBarWindows() {
-
- if (mShowBottom) {
- WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
- LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
- WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
- | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
- PixelFormat.TRANSLUCENT);
- lp.setTitle("CarNavigationBar");
- lp.windowAnimations = 0;
- mWindowManager.addView(mNavigationBarWindow, lp);
+ /**
+ * We register for soft keyboard visibility events such that we can hide the navigation bar
+ * giving more screen space to the IME. Note: this is optional and controlled by
+ * {@code com.android.internal.R.bool.config_automotiveHideNavBarForKeyboard}.
+ */
+ @Override
+ public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition,
+ boolean showImeSwitcher) {
+ if (!mHideNavBarForKeyboard) {
+ return;
}
+ if (mContext.getDisplay().getDisplayId() != displayId) {
+ return;
+ }
+
+ boolean isKeyboardVisible = (vis & InputMethodService.IME_VISIBLE) != 0;
+ if (!isKeyboardVisible) {
+ attachBottomNavBarWindow();
+ } else {
+ detachBottomNavBarWindow();
+ }
+ }
+
+ private void attachNavBarWindows() {
+ attachBottomNavBarWindow();
+
if (mShowLeft) {
int width = mContext.getResources().getDimensionPixelSize(
R.dimen.car_left_navigation_bar_width);
@@ -807,7 +837,41 @@
rightlp.gravity = Gravity.RIGHT;
mWindowManager.addView(mRightNavigationBarWindow, rightlp);
}
+ }
+ private void attachBottomNavBarWindow() {
+ if (!mShowBottom) {
+ return;
+ }
+
+ if (mBottomNavBarVisible) {
+ return;
+ }
+ mBottomNavBarVisible = true;
+
+ WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+ LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
+ WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+ | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+ | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
+ PixelFormat.TRANSLUCENT);
+ lp.setTitle("CarNavigationBar");
+ lp.windowAnimations = 0;
+ mWindowManager.addView(mNavigationBarWindow, lp);
+ }
+
+ private void detachBottomNavBarWindow() {
+ if (!mShowBottom) {
+ return;
+ }
+
+ if (!mBottomNavBarVisible) {
+ return;
+ }
+ mBottomNavBarVisible = false;
+ mWindowManager.removeView(mNavigationBarWindow);
}
private void buildBottomBar(int layout) {
@@ -957,8 +1021,12 @@
UserSwitcherController userSwitcherController =
Dependency.get(UserSwitcherController.class);
if (userSwitcherController.useFullscreenUserSwitcher()) {
+ Car car = Car.createCar(mContext);
+ CarTrustAgentEnrollmentManager enrollmentManager = (CarTrustAgentEnrollmentManager) car
+ .getCarManager(Car.CAR_TRUST_AGENT_ENROLLMENT_SERVICE);
mFullscreenUserSwitcher = new FullscreenUserSwitcher(this,
- mStatusBarWindow.findViewById(R.id.fullscreen_user_switcher_stub), mContext);
+ mStatusBarWindow.findViewById(R.id.fullscreen_user_switcher_stub),
+ enrollmentManager, mContext);
} else {
super.createUserSwitcher();
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarTrustAgentUnlockDialogHelper.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarTrustAgentUnlockDialogHelper.java
new file mode 100644
index 0000000..78bb1bc
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarTrustAgentUnlockDialogHelper.java
@@ -0,0 +1,240 @@
+/*
+ * 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.app.admin.DevicePolicyManager;
+import android.bluetooth.BluetoothAdapter;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.graphics.PixelFormat;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.internal.widget.LockPatternUtils;
+import com.android.systemui.R;
+
+/**
+ * A helper class displays an unlock dialog and receives broadcast about detecting trusted device
+ * & unlocking state to show the appropriate message on the dialog.
+ */
+class CarTrustAgentUnlockDialogHelper extends BroadcastReceiver{
+ private static final String TAG = CarTrustAgentUnlockDialogHelper.class.getSimpleName();
+
+ private final Context mContext;
+ private final WindowManager mWindowManager;
+ private final UserManager mUserManager;
+ private final WindowManager.LayoutParams mParams;
+ /**
+ * Not using Dialog because context passed from {@link FullscreenUserSwitcher} is not an
+ * activity.
+ */
+ private final View mUnlockDialog;
+ private final TextView mUnlockingText;
+ private final Button mButton;
+ private final IntentFilter mFilter;
+ private int mUid;
+ private boolean mIsDialogShowing;
+ private OnHideListener mOnHideListener;
+
+ CarTrustAgentUnlockDialogHelper(Context context) {
+ mContext = context;
+ mUserManager = mContext.getSystemService(UserManager.class);
+ mWindowManager = mContext.getSystemService(WindowManager.class);
+ mParams = createLayoutParams();
+ mFilter = getIntentFilter();
+
+ mParams.packageName = mContext.getPackageName();
+ mParams.setTitle(mContext.getString(R.string.unlock_dialog_title));
+
+ mUnlockDialog = LayoutInflater.from(mContext).inflate(
+ R.layout.trust_agent_unlock_dialog, null);
+ mUnlockDialog.setLayoutParams(mParams);
+
+ mUnlockingText = mUnlockDialog.findViewById(R.id.unlocking_text);
+ mButton = mUnlockDialog.findViewById(R.id.enter_pin_button);
+ mButton.setOnClickListener(v -> {
+ hideUnlockDialog(/* notifyOnHideListener= */true);
+ // TODO(b/138250105) Stop unlock advertising
+ });
+
+ BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+ if (bluetoothAdapter != null
+ && bluetoothAdapter.getLeState() == BluetoothAdapter.STATE_BLE_ON) {
+ mUnlockingText.setText(R.string.unlock_dialog_message_start);
+ }
+ }
+
+ /**
+ * This filter is listening on:
+ * {@link BluetoothAdapter#ACTION_BLE_STATE_CHANGED} for starting unlock advertising;
+ * {@link Intent#ACTION_USER_UNLOCKED} for IHU unlocked
+ */
+ private IntentFilter getIntentFilter() {
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(BluetoothAdapter.ACTION_BLE_STATE_CHANGED);
+ filter.addAction(Intent.ACTION_USER_UNLOCKED);
+ return filter;
+ }
+
+ /**
+ * Show dialog for the given user
+ */
+ void showUnlockDialog(int uid, OnHideListener listener) {
+ showUnlockDialogAfterDelay(uid, 0, listener);
+ }
+
+ /**
+ * Show dialog for the given user after the certain time of delay has elapsed
+ *
+ * @param uid the user to unlock
+ * @param listener listener that listens to dialog hide
+ */
+ void showUnlockDialogAfterDelay(int uid, OnHideListener listener) {
+ long delayMillis = mContext.getResources().getInteger(R.integer.unlock_dialog_delay_ms);
+ showUnlockDialogAfterDelay(uid, delayMillis, listener);
+ }
+
+ /**
+ * Show dialog for the given user after the supplied delay has elapsed
+ */
+ private void showUnlockDialogAfterDelay(int uid, long delayMillis, OnHideListener listener) {
+ setUid(uid);
+ mOnHideListener = listener;
+ if (!mIsDialogShowing) {
+ logd("Receiver registered");
+ mContext.registerReceiverAsUser(this, UserHandle.ALL, mFilter,
+ /* broadcastPermission= */ null,
+ /* scheduler= */ null);
+ new Handler().postDelayed(() -> {
+ if (!mUserManager.isUserUnlocked(uid)) {
+ logd("Showed unlock dialog for user: " + uid + " after " + delayMillis
+ + " delay.");
+ mWindowManager.addView(mUnlockDialog, mParams);
+ }
+ }, delayMillis);
+ }
+ mIsDialogShowing = true;
+ }
+
+ private void setUid(int uid) {
+ mUid = uid;
+ TextView userName = mUnlockDialog.findViewById(R.id.user_name);
+ userName.setText(mUserManager.getUserInfo(mUid).name);
+ ImageView avatar = mUnlockDialog.findViewById(R.id.avatar);
+ avatar.setImageBitmap(mUserManager.getUserIcon(mUid));
+ setButtonText();
+ }
+
+ private void hideUnlockDialog(boolean notifyOnHideListener) {
+ if (!mIsDialogShowing) {
+ return;
+ }
+ mWindowManager.removeView(mUnlockDialog);
+ logd("Receiver unregistered");
+ mContext.unregisterReceiver(this);
+ if (notifyOnHideListener && mOnHideListener != null) {
+ mOnHideListener.onHide();
+ }
+ mIsDialogShowing = false;
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action == null) {
+ return;
+ }
+ switch (action) {
+ case BluetoothAdapter.ACTION_BLE_STATE_CHANGED:
+ logd("Received ACTION_BLE_STATE_CHANGED");
+ int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
+ if (state == BluetoothAdapter.STATE_BLE_ON) {
+ logd("Received BLE_ON");
+ mUnlockingText.setText(R.string.unlock_dialog_message_start);
+ }
+ break;
+ case Intent.ACTION_USER_UNLOCKED:
+ int uid = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+ if (uid == mUid) {
+ logd("IHU unlocked");
+ hideUnlockDialog(/* notifyOnHideListener= */false);
+ } else {
+ Log.e(TAG, "Received ACTION_USER_UNLOCKED for unexpected uid: " + uid);
+ }
+ break;
+ default:
+ Log.e(TAG, "Encountered unexpected action when attempting to set "
+ + "unlock state message: " + action);
+ }
+ }
+
+ // Set button text based on security lock type
+ private void setButtonText() {
+ LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext);
+ int passwordQuality = lockPatternUtils.getActivePasswordQuality(mUid);
+ switch (passwordQuality) {
+ // PIN
+ case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
+ // Pattern
+ case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
+ mButton.setText(R.string.unlock_dialog_button_text_pattern);
+ break;
+ // Password
+ case DevicePolicyManager.PASSWORD_QUALITY_MANAGED:
+ mButton.setText(R.string.unlock_dialog_button_text_password);
+ break;
+ default:
+ Log.e(TAG, "Encountered unexpected security type when attempting to set "
+ + "button text:" + passwordQuality);
+ }
+ }
+
+ private WindowManager.LayoutParams createLayoutParams() {
+ return new WindowManager.LayoutParams(
+ WindowManager.LayoutParams.MATCH_PARENT,
+ WindowManager.LayoutParams.MATCH_PARENT,
+ WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG,
+ WindowManager.LayoutParams.FLAG_FULLSCREEN
+ | WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
+ | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION,
+ PixelFormat.TRANSLUCENT
+ );
+ }
+
+ private void logd(String message) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, message);
+ }
+ }
+
+ /**
+ * Listener used to notify when the dialog is hidden
+ */
+ interface OnHideListener {
+ void onHide();
+ }
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
index 0a167d9..7cd6adb 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
@@ -18,29 +18,60 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.car.trust.CarTrustAgentEnrollmentManager;
+import android.car.userlib.CarUserManagerHelper;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.UserInfo;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.Log;
import android.view.View;
import android.view.ViewStub;
import androidx.recyclerview.widget.GridLayoutManager;
import com.android.systemui.R;
+import com.android.systemui.statusbar.car.UserGridRecyclerView.UserRecord;
/**
* Manages the fullscreen user switcher.
*/
public class FullscreenUserSwitcher {
+ private static final String TAG = FullscreenUserSwitcher.class.getSimpleName();
+ // Because user 0 is headless, user count for single user is 2
+ private static final int NUMBER_OF_BACKGROUND_USERS = 1;
private final UserGridRecyclerView mUserGridView;
private final View mParent;
private final int mShortAnimDuration;
private final CarStatusBar mStatusBar;
+ private final Context mContext;
+ private final UserManager mUserManager;
+ private final CarTrustAgentEnrollmentManager mEnrollmentManager;
+ private CarTrustAgentUnlockDialogHelper mUnlockDialogHelper;
+ private UserGridRecyclerView.UserRecord mSelectedUser;
+ private CarUserManagerHelper mCarUserManagerHelper;
+ private final BroadcastReceiver mUserUnlockReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "user 0 is unlocked, SharedPreference is accessible.");
+ }
+ showDialogForInitialUser();
+ mContext.unregisterReceiver(mUserUnlockReceiver);
+ }
+ };
- public FullscreenUserSwitcher(CarStatusBar statusBar, ViewStub containerStub, Context context) {
+
+ public FullscreenUserSwitcher(CarStatusBar statusBar, ViewStub containerStub,
+ CarTrustAgentEnrollmentManager enrollmentManager, Context context) {
mStatusBar = statusBar;
mParent = containerStub.inflate();
- // Hide the user grid by default. It will only be made visible by clicking on a cancel
- // button in a bouncer.
- hide();
+ mEnrollmentManager = enrollmentManager;
+ mContext = context;
+
View container = mParent.findViewById(R.id.container);
// Initialize user grid.
@@ -50,9 +81,51 @@
mUserGridView.setLayoutManager(layoutManager);
mUserGridView.buildAdapter();
mUserGridView.setUserSelectionListener(this::onUserSelected);
+ mCarUserManagerHelper = new CarUserManagerHelper(context);
+ mUnlockDialogHelper = new CarTrustAgentUnlockDialogHelper(mContext);
+ mUserManager = mContext.getSystemService(UserManager.class);
mShortAnimDuration = container.getResources()
.getInteger(android.R.integer.config_shortAnimTime);
+ IntentFilter filter = new IntentFilter(Intent.ACTION_USER_UNLOCKED);
+ if (mUserManager.isUserUnlocked(UserHandle.USER_SYSTEM)) {
+ // User0 is unlocked, switched to the initial user
+ showDialogForInitialUser();
+ } else {
+ // listen to USER_UNLOCKED
+ mContext.registerReceiverAsUser(mUserUnlockReceiver,
+ UserHandle.getUserHandleForUid(UserHandle.USER_SYSTEM),
+ filter,
+ /* broadcastPermission= */ null,
+ /* scheduler */ null);
+ }
+ }
+
+ private void showDialogForInitialUser() {
+ int initialUser = mCarUserManagerHelper.getInitialUser();
+ UserInfo initialUserInfo = mUserManager.getUserInfo(initialUser);
+ mSelectedUser = new UserRecord(initialUserInfo,
+ /* isStartGuestSession= */ false,
+ /* isAddUser= */ false,
+ /* isForeground= */ true);
+ // For single user without trusted device, hide the user switcher.
+ if (!hasMultipleUsers() && !hasTrustedDevice(initialUser)) {
+ dismissUserSwitcher();
+ return;
+ }
+ // Show unlock dialog for initial user
+ if (hasTrustedDevice(initialUser)) {
+ mUnlockDialogHelper.showUnlockDialogAfterDelay(initialUser,
+ () -> dismissUserSwitcher());
+ }
+ }
+
+ /**
+ * Check if there is only one possible user to login in.
+ * In a Multi-User system there is always one background user (user 0)
+ */
+ private boolean hasMultipleUsers() {
+ return mUserManager.getUserCount() > NUMBER_OF_BACKGROUND_USERS + 1;
}
/**
@@ -77,14 +150,33 @@
}
/**
- * Every time user clicks on an item in the switcher, we hide the switcher, either
- * gradually or immediately.
+ * Every time user clicks on an item in the switcher, if the clicked user has no trusted device,
+ * we hide the switcher, either gradually or immediately.
*
- * We dismiss the entire keyguard if user clicked on the foreground user (user we're already
- * logged in as).
+ * If the user has trusted device, we show an unlock dialog to notify user the unlock state.
+ * When the unlock dialog is dismissed by user, we hide the unlock dialog and the switcher.
+ *
+ * We dismiss the entire keyguard when we hide the switcher if user clicked on the foreground
+ * user (user we're already logged in as).
*/
private void onUserSelected(UserGridRecyclerView.UserRecord record) {
- if (record.mIsForeground) {
+ mSelectedUser = record;
+ if (hasTrustedDevice(record.mInfo.id)) {
+ mUnlockDialogHelper.showUnlockDialog(record.mInfo.id, () -> dismissUserSwitcher());
+ return;
+ }
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "no trusted device enrolled for uid: " + record.mInfo.id);
+ }
+ dismissUserSwitcher();
+ }
+
+ private void dismissUserSwitcher() {
+ if (mSelectedUser == null) {
+ Log.e(TAG, "Request to dismiss user switcher, but no user selected");
+ return;
+ }
+ if (mSelectedUser.mIsForeground) {
hide();
mStatusBar.dismissKeyguard();
return;
@@ -106,4 +198,8 @@
});
}
+
+ private boolean hasTrustedDevice(int uid) {
+ return !mEnrollmentManager.getEnrolledDeviceInfoForUser(uid).isEmpty();
+ }
}
diff --git a/packages/SettingsLib/res/values/styles_support_preference.xml b/packages/SettingsLib/res/values/styles_support_preference.xml
index 5d787f8..6e61196 100644
--- a/packages/SettingsLib/res/values/styles_support_preference.xml
+++ b/packages/SettingsLib/res/values/styles_support_preference.xml
@@ -26,7 +26,7 @@
<item name="allowDividerAbove">true</item>
</style>
- <style name="PreferenceThemeOverlay.SettingsBase" parent="@style/PreferenceThemeOverlay.v14.Material">
+ <style name="PreferenceThemeOverlay.SettingsBase" parent="@style/PreferenceThemeOverlay">
<item name="footerPreferenceStyle">@style/Preference.FooterPreference.SettingsBase</item>
</style>
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index 3e359d2..d3bab5f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -224,7 +224,9 @@
mConnectivityManager = connectivityManager;
// check if verbose logging developer option has been turned on or off
- sVerboseLogging = mWifiManager != null && (mWifiManager.getVerboseLoggingLevel() > 0);
+ sVerboseLogging = Settings.Global.getInt(
+ mContext.getContentResolver(),
+ Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, 0) > 0;
mFilter = filter;
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 2286f4c..36e945f 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -34,7 +34,7 @@
import android.os.ParcelFileDescriptor;
import android.os.UserHandle;
import android.provider.Settings;
-import android.provider.SettingsValidators.Validator;
+import android.provider.settings.validators.Validator;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.BackupUtils;
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index e74ab05..00b2563 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -18,7 +18,9 @@
import android.annotation.NonNull;
import android.os.UserHandle;
+import android.provider.DeviceConfig;
import android.provider.Settings;
+import android.providers.settings.ConfigSettingsProto;
import android.providers.settings.GlobalSettingsProto;
import android.providers.settings.SecureSettingsProto;
import android.providers.settings.SettingProto;
@@ -28,24 +30,79 @@
import android.util.SparseBooleanArray;
import android.util.proto.ProtoOutputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
/** @hide */
class SettingsProtoDumpUtil {
+ private static final Map<String, Long> NAMESPACE_TO_FIELD_MAP = createNamespaceMap();
+
private SettingsProtoDumpUtil() {}
+ private static Map<String, Long> createNamespaceMap() {
+ Map<String, Long> namespaceToFieldMap = new HashMap<>();
+ namespaceToFieldMap.put(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ ConfigSettingsProto.ACTIVITY_MANAGER_SETTINGS);
+ namespaceToFieldMap.put(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
+ ConfigSettingsProto.ACTIVITY_MANAGER_NATIVE_BOOT_SETTINGS);
+ namespaceToFieldMap.put(DeviceConfig.NAMESPACE_APP_COMPAT,
+ ConfigSettingsProto.APP_COMPAT_SETTINGS);
+ namespaceToFieldMap.put(DeviceConfig.NAMESPACE_AUTOFILL,
+ ConfigSettingsProto.AUTOFILL_SETTINGS);
+ namespaceToFieldMap.put(DeviceConfig.NAMESPACE_CONNECTIVITY,
+ ConfigSettingsProto.CONNECTIVITY_SETTINGS);
+ namespaceToFieldMap.put(DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
+ ConfigSettingsProto.CONTENT_CAPTURE_SETTINGS);
+ namespaceToFieldMap.put(DeviceConfig.NAMESPACE_DEX_BOOT,
+ ConfigSettingsProto.DEX_BOOT_SETTINGS);
+ namespaceToFieldMap.put(DeviceConfig.NAMESPACE_GAME_DRIVER,
+ ConfigSettingsProto.GAME_DRIVER_SETTINGS);
+ namespaceToFieldMap.put(DeviceConfig.NAMESPACE_INPUT_NATIVE_BOOT,
+ ConfigSettingsProto.INPUT_NATIVE_BOOT_SETTINGS);
+ namespaceToFieldMap.put(DeviceConfig.NAMESPACE_NETD_NATIVE,
+ ConfigSettingsProto.NETD_NATIVE_SETTINGS);
+ namespaceToFieldMap.put(DeviceConfig.NAMESPACE_PRIVACY,
+ ConfigSettingsProto.PRIVACY_SETTINGS);
+ namespaceToFieldMap.put(DeviceConfig.NAMESPACE_ROLLBACK,
+ ConfigSettingsProto.ROLLBACK_SETTINGS);
+ namespaceToFieldMap.put(DeviceConfig.NAMESPACE_ROLLBACK_BOOT,
+ ConfigSettingsProto.ROLLBACK_BOOT_SETTINGS);
+ namespaceToFieldMap.put(DeviceConfig.NAMESPACE_RUNTIME,
+ ConfigSettingsProto.RUNTIME_SETTINGS);
+ namespaceToFieldMap.put(DeviceConfig.NAMESPACE_RUNTIME_NATIVE,
+ ConfigSettingsProto.RUNTIME_NATIVE_SETTINGS);
+ namespaceToFieldMap.put(DeviceConfig.NAMESPACE_RUNTIME_NATIVE_BOOT,
+ ConfigSettingsProto.RUNTIME_NATIVE_BOOT_SETTINGS);
+ namespaceToFieldMap.put(DeviceConfig.NAMESPACE_STORAGE,
+ ConfigSettingsProto.STORAGE_SETTINGS);
+ namespaceToFieldMap.put(DeviceConfig.NAMESPACE_SYSTEMUI,
+ ConfigSettingsProto.SYSTEMUI_SETTINGS);
+ namespaceToFieldMap.put(DeviceConfig.NAMESPACE_TELEPHONY,
+ ConfigSettingsProto.TELEPHONY_SETTINGS);
+ namespaceToFieldMap.put(DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
+ ConfigSettingsProto.TEXTCLASSIFIER_SETTINGS);
+ return Collections.unmodifiableMap(namespaceToFieldMap);
+ }
+
static void dumpProtoLocked(SettingsProvider.SettingsRegistry settingsRegistry,
ProtoOutputStream proto) {
// Config settings
SettingsState configSettings = settingsRegistry.getSettingsLocked(
SettingsProvider.SETTINGS_TYPE_CONFIG, UserHandle.USER_SYSTEM);
if (configSettings != null) {
- // TODO(b/113100523): dump configuration settings after they are added
+ dumpProtoConfigSettingsLocked(
+ proto, SettingsServiceDumpProto.CONFIG_SETTINGS, configSettings);
}
// Global settings
SettingsState globalSettings = settingsRegistry.getSettingsLocked(
SettingsProvider.SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM);
if (globalSettings != null) {
- dumpProtoGlobalSettingsLocked(proto, SettingsServiceDumpProto.GLOBAL_SETTINGS, globalSettings);
+ dumpProtoGlobalSettingsLocked(
+ proto, SettingsServiceDumpProto.GLOBAL_SETTINGS, globalSettings);
}
// Per-user settings
@@ -1547,9 +1604,6 @@
Settings.Global.WIFI_P2P_DEVICE_NAME,
GlobalSettingsProto.Wifi.P2P_DEVICE_NAME);
dumpSetting(s, p,
- Settings.Global.WIFI_REENABLE_DELAY_MS,
- GlobalSettingsProto.Wifi.REENABLE_DELAY_MS);
- dumpSetting(s, p,
Settings.Global.WIFI_EPHEMERAL_OUT_OF_RANGE_TIMEOUT_MS,
GlobalSettingsProto.Wifi.EPHEMERAL_OUT_OF_RANGE_TIMEOUT_MS);
dumpSetting(s, p,
@@ -1596,6 +1650,33 @@
// Settings.Global.INSTALL_NON_MARKET_APPS intentionally excluded since it's deprecated.
}
+ private static void dumpProtoConfigSettingsLocked(
+ @NonNull ProtoOutputStream p, long fieldId, @NonNull SettingsState s) {
+ Map<String, List<String>> namespaceMap = new HashMap<>();
+ final long token = p.start(fieldId);
+ s.dumpHistoricalOperations(p, ConfigSettingsProto.HISTORICAL_OPERATIONS);
+ for (String name : s.getSettingNamesLocked()) {
+ String namespace = name.substring(0, name.indexOf('/'));
+ if (NAMESPACE_TO_FIELD_MAP.containsKey(namespace)) {
+ dumpSetting(s, p, name, NAMESPACE_TO_FIELD_MAP.get(namespace));
+ } else {
+ if (!namespaceMap.containsKey(namespace)) {
+ namespaceMap.put(namespace, new ArrayList<>());
+ }
+ namespaceMap.get(namespace).add(name);
+ }
+ }
+ for (String namespace : namespaceMap.keySet()) {
+ final long namespacesToken = p.start(ConfigSettingsProto.EXTRA_NAMESPACES);
+ p.write(ConfigSettingsProto.NamespaceProto.NAMESPACE, namespace);
+ for (String name : namespaceMap.get(namespace)) {
+ dumpSetting(s, p, name, ConfigSettingsProto.NamespaceProto.SETTINGS);
+ }
+ p.end(namespacesToken);
+ }
+ p.end(token);
+ }
+
/** Dumps settings that use a common prefix into a repeated field. */
private static void dumpRepeatedSetting(@NonNull SettingsState settings,
@NonNull ProtoOutputStream proto, String settingPrefix, long fieldId) {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 7016d30..e492e28 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -70,7 +70,7 @@
import android.provider.Settings;
import android.provider.Settings.Global;
import android.provider.Settings.Secure;
-import android.provider.SettingsValidators;
+import android.provider.settings.validators.Validator;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -314,11 +314,6 @@
public boolean onCreate() {
Settings.setInSystemServer();
- // fail to boot if there're any backed up settings that don't have a non-null validator
- ensureAllBackedUpSystemSettingsHaveValidators();
- ensureAllBackedUpGlobalSettingsHaveValidators();
- ensureAllBackedUpSecureSettingsHaveValidators();
-
synchronized (mLock) {
mUserManager = UserManager.get(getContext());
mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
@@ -338,57 +333,6 @@
return true;
}
- private void ensureAllBackedUpSystemSettingsHaveValidators() {
- String offenders = getOffenders(concat(Settings.System.SETTINGS_TO_BACKUP,
- Settings.System.LEGACY_RESTORE_SETTINGS), Settings.System.VALIDATORS);
-
- failToBootIfOffendersPresent(offenders, "Settings.System");
- }
-
- private void ensureAllBackedUpGlobalSettingsHaveValidators() {
- String offenders = getOffenders(concat(Settings.Global.SETTINGS_TO_BACKUP,
- Settings.Global.LEGACY_RESTORE_SETTINGS), Settings.Global.VALIDATORS);
-
- failToBootIfOffendersPresent(offenders, "Settings.Global");
- }
-
- private void ensureAllBackedUpSecureSettingsHaveValidators() {
- String offenders = getOffenders(concat(Settings.Secure.SETTINGS_TO_BACKUP,
- Settings.Secure.LEGACY_RESTORE_SETTINGS), Settings.Secure.VALIDATORS);
-
- failToBootIfOffendersPresent(offenders, "Settings.Secure");
- }
-
- private void failToBootIfOffendersPresent(String offenders, String settingsType) {
- if (offenders.length() > 0) {
- throw new RuntimeException("All " + settingsType + " settings that are backed up"
- + " have to have a non-null validator, but those don't: " + offenders);
- }
- }
-
- private String getOffenders(String[] settingsToBackup, Map<String,
- SettingsValidators.Validator> validators) {
- StringBuilder offenders = new StringBuilder();
- for (String setting : settingsToBackup) {
- if (validators.get(setting) == null) {
- offenders.append(setting).append(" ");
- }
- }
- return offenders.toString();
- }
-
- private final String[] concat(String[] first, String[] second) {
- if (second == null || second.length == 0) {
- return first;
- }
- final int firstLen = first.length;
- final int secondLen = second.length;
- String[] both = new String[firstLen + secondLen];
- System.arraycopy(first, 0, both, 0, firstLen);
- System.arraycopy(second, 0, both, firstLen, secondLen);
- return both;
- }
-
@Override
public Bundle call(String method, String name, Bundle args) {
final int requestingUserId = getRequestingUserId(args);
@@ -1773,7 +1717,7 @@
}
private void validateSystemSettingValue(String name, String value) {
- SettingsValidators.Validator validator = Settings.System.VALIDATORS.get(name);
+ Validator validator = Settings.System.VALIDATORS.get(name);
if (validator != null && !validator.validate(value)) {
throw new IllegalArgumentException("Invalid value: " + value
+ " for setting: " + name);
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 58e1d47..8c0108d 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -352,10 +352,10 @@
private final BugreportInfo mInfo;
- BugreportCallbackImpl(String name) {
+ BugreportCallbackImpl(String name, @Nullable String title, @Nullable String description) {
// pid not used in this workflow, so setting default = 0
mInfo = new BugreportInfo(mContext, 0 /* pid */, name,
- 100 /* max progress*/);
+ 100 /* max progress*/, title, description);
}
@Override
@@ -578,6 +578,8 @@
}
int bugreportType = intent.getIntExtra(EXTRA_BUGREPORT_TYPE,
BugreportParams.BUGREPORT_MODE_INTERACTIVE);
+ String shareTitle = intent.getStringExtra(EXTRA_TITLE);
+ String shareDescription = intent.getStringExtra(EXTRA_DESCRIPTION);
ParcelFileDescriptor screenshotFd = createReadWriteFile(BUGREPORT_DIR,
bugreportName + ".png");
@@ -595,7 +597,8 @@
+ " bugreport file fd: " + bugreportFd
+ " screenshot file fd: " + screenshotFd);
- BugreportCallbackImpl bugreportCallback = new BugreportCallbackImpl(bugreportName);
+ BugreportCallbackImpl bugreportCallback = new BugreportCallbackImpl(bugreportName,
+ shareTitle, shareDescription);
try {
mBugreportManager.startBugreport(bugreportFd, screenshotFd,
new BugreportParams(bugreportType), executor, bugreportCallback);
@@ -982,7 +985,10 @@
}
screenshotFile = null;
}
- onBugreportFinished(id, bugreportFile, screenshotFile, info.title, info.description, max);
+ // TODO: Since we are passing id to the function, it should be able to find the info linked
+ // to the id and therefore use the value of shareTitle and shareDescription.
+ onBugreportFinished(id, bugreportFile, screenshotFile, info.shareTitle,
+ info.shareDescription, max);
}
@@ -1844,6 +1850,14 @@
String title;
/**
+ * One-line summary of the bug; when set, will be used as the subject of the
+ * {@link Intent#ACTION_SEND_MULTIPLE} intent. This is the predefined title which is
+ * set initially when the request to take a bugreport is made. This overrides any changes
+ * in the title that the user makes after the bugreport starts.
+ */
+ String shareTitle;
+
+ /**
* User-provided, detailed description of the bugreport; when set, will be added to the body
* of the {@link Intent#ACTION_SEND_MULTIPLE} intent.
*/
@@ -1906,7 +1920,9 @@
int screenshotCounter;
/**
- * Descriptive text that will be shown to the user in the notification message.
+ * Descriptive text that will be shown to the user in the notification message. This is the
+ * predefined description which is set initially when the request to take a bugreport is
+ * made.
*/
String shareDescription;
@@ -1914,18 +1930,21 @@
* Constructor for tracked bugreports - typically called upon receiving BUGREPORT_STARTED.
*/
BugreportInfo(Context context, int id, int pid, String name, int max) {
- this(context, pid, name, max);
+ this(context, pid, name, max, null, null);
this.id = id;
}
/**
* Constructor for tracked bugreports - typically called upon receiving BUGREPORT_REQUESTED.
*/
- BugreportInfo(Context context, int pid, String name, int max) {
+ BugreportInfo(Context context, int pid, String name, int max, @Nullable String shareTitle,
+ @Nullable String shareDescription) {
this.context = context;
this.pid = pid;
this.name = name;
this.max = this.realMax = max;
+ this.shareTitle = shareTitle == null ? "" : shareTitle;
+ this.shareDescription = shareDescription == null ? "" : shareDescription;
}
/**
@@ -2019,6 +2038,7 @@
.append("\n\taddingDetailsToZip: ").append(addingDetailsToZip)
.append(" addedDetailsToZip: ").append(addedDetailsToZip)
.append("\n\tshareDescription: ").append(shareDescription)
+ .append("\n\tshareTitle: ").append(shareTitle)
.toString();
}
@@ -2046,6 +2066,7 @@
finished = in.readInt() == 1;
screenshotCounter = in.readInt();
shareDescription = in.readString();
+ shareTitle = in.readString();
}
@Override
@@ -2071,6 +2092,7 @@
dest.writeInt(finished ? 1 : 0);
dest.writeInt(screenshotCounter);
dest.writeString(shareDescription);
+ dest.writeString(shareTitle);
}
@Override
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index fab7242..19e682b 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1386,6 +1386,8 @@
buttons</string>
<string name="screen_pinning_toast_recents_invisible">To unpin this screen, touch & hold Back
and Home buttons</string>
+ <!-- Notify (in toast) user how to unpin screen in gesture navigation mode [CHAR LIMIT=NONE] -->
+ <string name="screen_pinning_toast_gesture_nav">To unpin this screen, swipe up & hold</string>
<!-- Screen pinning positive response. -->
<string name="screen_pinning_positive">Got it</string>
<!-- Screen pinning negative response. -->
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
index c732584..08996c3 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
@@ -188,9 +188,8 @@
if ((sysuiStateFlags & SYSUI_STATE_BOUNCER_SHOWING) != 0) {
return false;
}
- // Disable when in screen pinning, immersive, or the notifications are interactive
- int disableFlags = SYSUI_STATE_SCREEN_PINNING
- | SYSUI_STATE_NAV_BAR_HIDDEN
+ // Disable when in immersive, or the notifications are interactive
+ int disableFlags = SYSUI_STATE_NAV_BAR_HIDDEN
| SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED
| SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING;
return (sysuiStateFlags & disableFlags) != 0;
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 0ee9bff..59270a0 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -34,6 +34,7 @@
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.systemui.appops.AppOpsController;
import com.android.systemui.assist.AssistManager;
+import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dock.DockManager;
@@ -200,6 +201,7 @@
@Inject Lazy<ActivityStarter> mActivityStarter;
@Inject Lazy<ActivityStarterDelegate> mActivityStarterDelegate;
+ @Inject Lazy<BroadcastDispatcher> mBroadcastDispatcher;
@Inject Lazy<AsyncSensorManager> mAsyncSensorManager;
@Inject Lazy<BluetoothController> mBluetoothController;
@Inject Lazy<LocationController> mLocationController;
@@ -317,6 +319,7 @@
mProviders.put(MAIN_HANDLER, mMainHandler::get);
mProviders.put(ActivityStarter.class, mActivityStarter::get);
mProviders.put(ActivityStarterDelegate.class, mActivityStarterDelegate::get);
+ mProviders.put(BroadcastDispatcher.class, mBroadcastDispatcher::get);
mProviders.put(AsyncSensorManager.class, mAsyncSensorManager::get);
@@ -496,6 +499,7 @@
// Make sure that the DumpController gets added to mDependencies, as they are only added
// with Dependency#get.
getDependency(DumpController.class);
+ getDependency(BroadcastDispatcher.class);
// If an arg is specified, try to dump the dependency
String controller = args != null && args.length > 1
diff --git a/packages/SystemUI/src/com/android/systemui/assist/ui/InvocationLightsView.java b/packages/SystemUI/src/com/android/systemui/assist/ui/InvocationLightsView.java
index bc782a7..bb3bd78 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/ui/InvocationLightsView.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/ui/InvocationLightsView.java
@@ -100,7 +100,9 @@
int cornerRadiusBottom = DisplayUtils.getCornerRadiusBottom(context);
int cornerRadiusTop = DisplayUtils.getCornerRadiusTop(context);
- mViewHeight = Math.max(cornerRadiusBottom, cornerRadiusTop);
+ // ensure that height is non-zero even for square corners
+ mViewHeight = Math.max(Math.max(cornerRadiusBottom, cornerRadiusTop),
+ DisplayUtils.convertDpToPx(LIGHT_HEIGHT_DP, context));
final int dualToneDarkTheme = Utils.getThemeAttr(mContext, R.attr.darkIconTheme);
final int dualToneLightTheme = Utils.getThemeAttr(mContext, R.attr.lightIconTheme);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialog.java b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialog.java
new file mode 100644
index 0000000..d4baefd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialog.java
@@ -0,0 +1,108 @@
+/*
+ * 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.biometrics;
+
+import android.hardware.biometrics.BiometricPrompt;
+import android.os.Bundle;
+import android.view.WindowManager;
+
+import com.android.systemui.biometrics.ui.BiometricDialogView;
+
+/**
+ * Interface for the biometric dialog UI.
+ */
+public interface BiometricDialog {
+
+ // TODO: Clean up save/restore state
+ String[] KEYS_TO_BACKUP = {
+ BiometricPrompt.KEY_TITLE,
+ BiometricPrompt.KEY_USE_DEFAULT_TITLE,
+ BiometricPrompt.KEY_SUBTITLE,
+ BiometricPrompt.KEY_DESCRIPTION,
+ BiometricPrompt.KEY_POSITIVE_TEXT,
+ BiometricPrompt.KEY_NEGATIVE_TEXT,
+ BiometricPrompt.KEY_REQUIRE_CONFIRMATION,
+ BiometricPrompt.KEY_ALLOW_DEVICE_CREDENTIAL,
+ BiometricPrompt.KEY_FROM_CONFIRM_DEVICE_CREDENTIAL,
+
+ BiometricDialogView.KEY_TRY_AGAIN_VISIBILITY,
+ BiometricDialogView.KEY_CONFIRM_VISIBILITY,
+ BiometricDialogView.KEY_CONFIRM_ENABLED,
+ BiometricDialogView.KEY_STATE,
+ BiometricDialogView.KEY_ERROR_TEXT_VISIBILITY,
+ BiometricDialogView.KEY_ERROR_TEXT_STRING,
+ BiometricDialogView.KEY_ERROR_TEXT_IS_TEMPORARY,
+ BiometricDialogView.KEY_ERROR_TEXT_COLOR,
+ };
+
+ /**
+ * Show the dialog.
+ * @param wm
+ * @param skipIntroAnimation
+ */
+ void show(WindowManager wm, boolean skipIntroAnimation);
+
+ /**
+ * Dismiss the dialog without sending a callback.
+ */
+ void dismissWithoutCallback(boolean animate);
+
+ /**
+ * Dismiss the dialog. Animate away.
+ */
+ void dismissFromSystemServer();
+
+ /**
+ * Biometric authenticated. May be pending user confirmation, or completed.
+ */
+ void onAuthenticationSucceeded();
+
+ /**
+ * Authentication failed (reject, timeout). Dialog stays showing.
+ * @param failureReason
+ */
+ void onAuthenticationFailed(String failureReason);
+
+ /**
+ * Authentication rejected, or help message received.
+ * @param help
+ */
+ void onHelp(String help);
+
+ /**
+ * Authentication failed. Dialog going away.
+ * @param error
+ */
+ void onError(String error);
+
+ /**
+ * Save the current state.
+ * @param outState
+ */
+ void onSaveState(Bundle outState);
+
+ /**
+ * Restore a previous state.
+ * @param savedState
+ */
+ void restoreState(Bundle savedState);
+
+ /**
+ * Get the client's package name
+ */
+ String getOpPackageName();
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java
index e66a8fa..a8e5722 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java
@@ -16,137 +16,156 @@
package com.android.systemui.biometrics;
+import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
+import android.app.IActivityTaskManager;
+import android.app.TaskStackListener;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
-import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricPrompt;
import android.hardware.biometrics.IBiometricServiceReceiverInternal;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
-import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
import android.view.WindowManager;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.SomeArgs;
-import com.android.systemui.Dependency;
import com.android.systemui.SystemUI;
-import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.biometrics.ui.BiometricDialogView;
import com.android.systemui.statusbar.CommandQueue;
+import java.util.List;
+
/**
- * Receives messages sent from AuthenticationClient and shows the appropriate biometric UI (e.g.
- * BiometricDialogView).
+ * Receives messages sent from {@link com.android.server.biometrics.BiometricService} and shows the
+ * appropriate biometric UI (e.g. BiometricDialogView).
*/
-public class BiometricDialogImpl extends SystemUI implements CommandQueue.Callbacks {
+public class BiometricDialogImpl extends SystemUI implements CommandQueue.Callbacks,
+ DialogViewCallback {
private static final String TAG = "BiometricDialogImpl";
private static final boolean DEBUG = true;
- private static final int MSG_SHOW_DIALOG = 1;
- private static final int MSG_BIOMETRIC_AUTHENTICATED = 2;
- private static final int MSG_BIOMETRIC_HELP = 3;
- private static final int MSG_BIOMETRIC_ERROR = 4;
- private static final int MSG_HIDE_DIALOG = 5;
- private static final int MSG_BUTTON_NEGATIVE = 6;
- private static final int MSG_USER_CANCELED = 7;
- private static final int MSG_BUTTON_POSITIVE = 8;
- private static final int MSG_TRY_AGAIN_PRESSED = 9;
+ private final Injector mInjector;
+ // TODO: These should just be saved from onSaveState
private SomeArgs mCurrentDialogArgs;
- private BiometricDialogView mCurrentDialog;
+ @VisibleForTesting
+ BiometricDialog mCurrentDialog;
+
+ private Handler mHandler = new Handler(Looper.getMainLooper());
private WindowManager mWindowManager;
- private IBiometricServiceReceiverInternal mReceiver;
- private boolean mDialogShowing;
- private Callback mCallback = new Callback();
- private WakefulnessLifecycle mWakefulnessLifecycle;
+ @VisibleForTesting
+ IActivityTaskManager mActivityTaskManager;
+ @VisibleForTesting
+ BiometricTaskStackListener mTaskStackListener;
+ @VisibleForTesting
+ IBiometricServiceReceiverInternal mReceiver;
- private Handler mHandler = new Handler(Looper.getMainLooper()) {
+ public class BiometricTaskStackListener extends TaskStackListener {
@Override
- public void handleMessage(Message msg) {
- switch(msg.what) {
- case MSG_SHOW_DIALOG:
- handleShowDialog((SomeArgs) msg.obj, false /* skipAnimation */,
- null /* savedState */);
- break;
- case MSG_BIOMETRIC_AUTHENTICATED: {
- SomeArgs args = (SomeArgs) msg.obj;
- handleBiometricAuthenticated((boolean) args.arg1 /* authenticated */,
- (String) args.arg2 /* failureReason */);
- args.recycle();
- break;
- }
- case MSG_BIOMETRIC_HELP: {
- SomeArgs args = (SomeArgs) msg.obj;
- handleBiometricHelp((String) args.arg1 /* message */);
- args.recycle();
- break;
- }
- case MSG_BIOMETRIC_ERROR:
- handleBiometricError((String) msg.obj);
- break;
- case MSG_HIDE_DIALOG:
- handleHideDialog((Boolean) msg.obj);
- break;
- case MSG_BUTTON_NEGATIVE:
- handleButtonNegative();
- break;
- case MSG_USER_CANCELED:
- handleUserCanceled();
- break;
- case MSG_BUTTON_POSITIVE:
- handleButtonPositive();
- break;
- case MSG_TRY_AGAIN_PRESSED:
- handleTryAgainPressed();
- break;
- default:
- Log.w(TAG, "Unknown message: " + msg.what);
- break;
- }
- }
- };
-
- private class Callback implements DialogViewCallback {
- @Override
- public void onUserCanceled() {
- mHandler.obtainMessage(MSG_USER_CANCELED).sendToTarget();
- }
-
- @Override
- public void onErrorShown() {
- mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_HIDE_DIALOG,
- false /* userCanceled */), BiometricPrompt.HIDE_DIALOG_DELAY);
- }
-
- @Override
- public void onNegativePressed() {
- mHandler.obtainMessage(MSG_BUTTON_NEGATIVE).sendToTarget();
- }
-
- @Override
- public void onPositivePressed() {
- mHandler.obtainMessage(MSG_BUTTON_POSITIVE).sendToTarget();
- }
-
- @Override
- public void onTryAgainPressed() {
- mHandler.obtainMessage(MSG_TRY_AGAIN_PRESSED).sendToTarget();
+ public void onTaskStackChanged() {
+ mHandler.post(mTaskStackChangedRunnable);
}
}
- final WakefulnessLifecycle.Observer mWakefulnessObserver = new WakefulnessLifecycle.Observer() {
- @Override
- public void onStartedGoingToSleep() {
- if (mDialogShowing) {
- if (DEBUG) Log.d(TAG, "User canceled due to screen off");
- mHandler.obtainMessage(MSG_USER_CANCELED).sendToTarget();
+ private final Runnable mTaskStackChangedRunnable = () -> {
+ if (mCurrentDialog != null) {
+ try {
+ final String clientPackage = mCurrentDialog.getOpPackageName();
+ Log.w(TAG, "Task stack changed, current client: " + clientPackage);
+ final List<ActivityManager.RunningTaskInfo> runningTasks =
+ mActivityTaskManager.getTasks(1);
+ if (!runningTasks.isEmpty()) {
+ final String topPackage = runningTasks.get(0).topActivity.getPackageName();
+ if (!topPackage.contentEquals(clientPackage)) {
+ Log.w(TAG, "Evicting client due to: " + topPackage);
+ mCurrentDialog.dismissWithoutCallback(true /* animate */);
+ mCurrentDialog = null;
+ mReceiver.onDialogDismissed(BiometricPrompt.DISMISSED_REASON_USER_CANCEL);
+ mReceiver = null;
+ }
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Remote exception", e);
}
}
};
@Override
+ public void onTryAgainPressed() {
+ try {
+ mReceiver.onTryAgainPressed();
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException when handling try again", e);
+ }
+ }
+
+ @Override
+ public void onDismissed(@DismissedReason int reason) {
+ switch (reason) {
+ case DialogViewCallback.DISMISSED_USER_CANCELED:
+ sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_USER_CANCEL);
+ break;
+
+ case DialogViewCallback.DISMISSED_BUTTON_NEGATIVE:
+ sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_NEGATIVE);
+ break;
+
+ case DialogViewCallback.DISMISSED_BUTTON_POSITIVE:
+ sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_CONFIRMED);
+ break;
+
+ case DialogViewCallback.DISMISSED_AUTHENTICATED:
+ sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_CONFIRM_NOT_REQUIRED);
+ break;
+
+ case DialogViewCallback.DISMISSED_ERROR:
+ sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_ERROR);
+ break;
+
+ case DialogViewCallback.DISMISSED_BY_SYSTEM_SERVER:
+ sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_SERVER_REQUESTED);
+ break;
+
+ default:
+ Log.e(TAG, "Unhandled reason: " + reason);
+ break;
+ }
+ }
+
+ private void sendResultAndCleanUp(@DismissedReason int reason) {
+ if (mReceiver == null) {
+ Log.e(TAG, "Receiver is null");
+ return;
+ }
+ try {
+ mReceiver.onDialogDismissed(reason);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Remote exception", e);
+ }
+ onDialogDismissed(reason);
+ }
+
+ public static class Injector {
+ IActivityTaskManager getActivityTaskManager() {
+ return ActivityTaskManager.getService();
+ }
+ }
+
+ public BiometricDialogImpl() {
+ this(new Injector());
+ }
+
+ @VisibleForTesting
+ BiometricDialogImpl(Injector injector) {
+ mInjector = injector;
+ }
+
+ @Override
public void start() {
final PackageManager pm = mContext.getPackageManager();
if (pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)
@@ -154,30 +173,38 @@
|| pm.hasSystemFeature(PackageManager.FEATURE_IRIS)) {
getComponent(CommandQueue.class).addCallback(this);
mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
- mWakefulnessLifecycle = Dependency.get(WakefulnessLifecycle.class);
- mWakefulnessLifecycle.addObserver(mWakefulnessObserver);
+ mActivityTaskManager = mInjector.getActivityTaskManager();
+
+ try {
+ mTaskStackListener = new BiometricTaskStackListener();
+ mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Unable to register task stack listener", e);
+ }
}
}
@Override
public void showBiometricDialog(Bundle bundle, IBiometricServiceReceiverInternal receiver,
- int type, boolean requireConfirmation, int userId) {
+ int type, boolean requireConfirmation, int userId, String opPackageName) {
if (DEBUG) {
Log.d(TAG, "showBiometricDialog, type: " + type
+ ", requireConfirmation: " + requireConfirmation);
}
- // Remove these messages as they are part of the previous client
- mHandler.removeMessages(MSG_BIOMETRIC_ERROR);
- mHandler.removeMessages(MSG_BIOMETRIC_HELP);
- mHandler.removeMessages(MSG_BIOMETRIC_AUTHENTICATED);
- mHandler.removeMessages(MSG_HIDE_DIALOG);
SomeArgs args = SomeArgs.obtain();
args.arg1 = bundle;
args.arg2 = receiver;
args.argi1 = type;
args.arg3 = requireConfirmation;
args.argi2 = userId;
- mHandler.obtainMessage(MSG_SHOW_DIALOG, args).sendToTarget();
+ args.arg4 = opPackageName;
+
+ boolean skipAnimation = false;
+ if (mCurrentDialog != null) {
+ Log.w(TAG, "mCurrentDialog: " + mCurrentDialog);
+ skipAnimation = true;
+ }
+ showDialog(args, skipAnimation, null /* savedState */);
}
@Override
@@ -185,185 +212,111 @@
if (DEBUG) Log.d(TAG, "onBiometricAuthenticated: " + authenticated
+ " reason: " + failureReason);
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = authenticated;
- args.arg2 = failureReason;
- mHandler.obtainMessage(MSG_BIOMETRIC_AUTHENTICATED, args).sendToTarget();
- }
-
- @Override
- public void onBiometricHelp(String message) {
- if (DEBUG) Log.d(TAG, "onBiometricHelp: " + message);
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = message;
- mHandler.obtainMessage(MSG_BIOMETRIC_HELP, args).sendToTarget();
- }
-
- @Override
- public void onBiometricError(String error) {
- if (DEBUG) Log.d(TAG, "onBiometricError: " + error);
- mHandler.obtainMessage(MSG_BIOMETRIC_ERROR, error).sendToTarget();
- }
-
- @Override
- public void hideBiometricDialog() {
- if (DEBUG) Log.d(TAG, "hideBiometricDialog");
- mHandler.obtainMessage(MSG_HIDE_DIALOG, false /* userCanceled */).sendToTarget();
- }
-
- private void handleShowDialog(SomeArgs args, boolean skipAnimation, Bundle savedState) {
- mCurrentDialogArgs = args;
- final int type = args.argi1;
-
- // Create a new dialog but do not replace the current one yet.
- BiometricDialogView newDialog;
- if (type == BiometricAuthenticator.TYPE_FINGERPRINT) {
- newDialog = new FingerprintDialogView(mContext, mCallback);
- } else if (type == BiometricAuthenticator.TYPE_FACE) {
- newDialog = new FaceDialogView(mContext, mCallback);
- } else {
- Log.e(TAG, "Unsupported type: " + type);
- return;
- }
-
- if (DEBUG) Log.d(TAG, "handleShowDialog, "
- + " savedState: " + savedState
- + " mCurrentDialog: " + mCurrentDialog
- + " newDialog: " + newDialog
- + " type: " + type);
-
- if (savedState != null) {
- // SavedState is only non-null if it's from onConfigurationChanged. Restore the state
- // even though it may be removed / re-created again
- newDialog.restoreState(savedState);
- } else if (mCurrentDialog != null && mDialogShowing) {
- // If somehow we're asked to show a dialog, the old one doesn't need to be animated
- // away. This can happen if the app cancels and re-starts auth during configuration
- // change. This is ugly because we also have to do things on onConfigurationChanged
- // here.
- mCurrentDialog.forceRemove();
- }
-
- mReceiver = (IBiometricServiceReceiverInternal) args.arg2;
- newDialog.setBundle((Bundle) args.arg1);
- newDialog.setRequireConfirmation((boolean) args.arg3);
- newDialog.setUserId(args.argi2);
- newDialog.setSkipIntro(skipAnimation);
- mCurrentDialog = newDialog;
- mWindowManager.addView(mCurrentDialog, mCurrentDialog.getLayoutParams());
- mDialogShowing = true;
- }
-
- private void handleBiometricAuthenticated(boolean authenticated, String failureReason) {
- if (DEBUG) Log.d(TAG, "handleBiometricAuthenticated: " + authenticated);
-
if (authenticated) {
- mCurrentDialog.announceForAccessibility(
- mContext.getResources()
- .getText(mCurrentDialog.getAuthenticatedAccessibilityResourceId()));
- if (mCurrentDialog.requiresConfirmation()) {
- mCurrentDialog.updateState(BiometricDialogView.STATE_PENDING_CONFIRMATION);
- } else {
- mCurrentDialog.updateState(BiometricDialogView.STATE_AUTHENTICATED);
- mHandler.postDelayed(() -> {
- handleHideDialog(false /* userCanceled */);
- }, mCurrentDialog.getDelayAfterAuthenticatedDurationMs());
- }
+ mCurrentDialog.onAuthenticationSucceeded();
} else {
mCurrentDialog.onAuthenticationFailed(failureReason);
}
}
- private void handleBiometricHelp(String message) {
- if (DEBUG) Log.d(TAG, "handleBiometricHelp: " + message);
- mCurrentDialog.onHelpReceived(message);
+ @Override
+ public void onBiometricHelp(String message) {
+ if (DEBUG) Log.d(TAG, "onBiometricHelp: " + message);
+
+ mCurrentDialog.onHelp(message);
}
- private void handleBiometricError(String error) {
- if (DEBUG) Log.d(TAG, "handleBiometricError: " + error);
- if (!mDialogShowing) {
- if (DEBUG) Log.d(TAG, "Dialog already dismissed");
- return;
- }
- mCurrentDialog.onErrorReceived(error);
+ @Override
+ public void onBiometricError(String error) {
+ if (DEBUG) Log.d(TAG, "onBiometricError: " + error);
+ mCurrentDialog.onError(error);
}
- private void handleHideDialog(boolean userCanceled) {
- if (DEBUG) Log.d(TAG, "handleHideDialog, userCanceled: " + userCanceled);
- if (!mDialogShowing) {
- // This can happen if there's a race and we get called from both
- // onAuthenticated and onError, etc.
- Log.w(TAG, "Dialog already dismissed, userCanceled: " + userCanceled);
+ @Override
+ public void hideBiometricDialog() {
+ if (DEBUG) Log.d(TAG, "hideBiometricDialog");
+
+ mCurrentDialog.dismissFromSystemServer();
+ }
+
+ private void showDialog(SomeArgs args, boolean skipAnimation, Bundle savedState) {
+ mCurrentDialogArgs = args;
+ final int type = args.argi1;
+ final Bundle biometricPromptBundle = (Bundle) args.arg1;
+ final boolean requireConfirmation = (boolean) args.arg3;
+ final int userId = args.argi2;
+ final String opPackageName = (String) args.arg4;
+
+ // Create a new dialog but do not replace the current one yet.
+ final BiometricDialog newDialog = buildDialog(
+ biometricPromptBundle,
+ requireConfirmation,
+ userId,
+ type,
+ opPackageName);
+
+ if (newDialog == null) {
+ Log.e(TAG, "Unsupported type: " + type);
return;
}
- if (userCanceled) {
- try {
- mReceiver.onDialogDismissed(BiometricPrompt.DISMISSED_REASON_USER_CANCEL);
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException when hiding dialog", e);
- }
+
+ if (DEBUG) {
+ Log.d(TAG, "showDialog, "
+ + " savedState: " + savedState
+ + " mCurrentDialog: " + mCurrentDialog
+ + " newDialog: " + newDialog
+ + " type: " + type);
+ }
+
+ if (savedState != null) {
+ // SavedState is only non-null if it's from onConfigurationChanged. Restore the state
+ // even though it may be removed / re-created again
+ newDialog.restoreState(savedState);
+ } else if (mCurrentDialog != null) {
+ // If somehow we're asked to show a dialog, the old one doesn't need to be animated
+ // away. This can happen if the app cancels and re-starts auth during configuration
+ // change. This is ugly because we also have to do things on onConfigurationChanged
+ // here.
+ mCurrentDialog.dismissWithoutCallback(false /* animate */);
+ }
+
+ mReceiver = (IBiometricServiceReceiverInternal) args.arg2;
+ mCurrentDialog = newDialog;
+ mCurrentDialog.show(mWindowManager, skipAnimation);
+ }
+
+ private void onDialogDismissed(@DismissedReason int reason) {
+ if (DEBUG) Log.d(TAG, "onDialogDismissed: " + reason);
+ if (mCurrentDialog == null) {
+ Log.w(TAG, "Dialog already dismissed");
}
mReceiver = null;
- mDialogShowing = false;
- mCurrentDialog.startDismiss();
- }
-
- private void handleButtonNegative() {
- if (mReceiver == null) {
- Log.e(TAG, "Receiver is null");
- return;
- }
- try {
- mReceiver.onDialogDismissed(BiometricPrompt.DISMISSED_REASON_NEGATIVE);
- } catch (RemoteException e) {
- Log.e(TAG, "Remote exception when handling negative button", e);
- }
- handleHideDialog(false /* userCanceled */);
- }
-
- private void handleButtonPositive() {
- if (mReceiver == null) {
- Log.e(TAG, "Receiver is null");
- return;
- }
- try {
- mReceiver.onDialogDismissed(BiometricPrompt.DISMISSED_REASON_POSITIVE);
- } catch (RemoteException e) {
- Log.e(TAG, "Remote exception when handling positive button", e);
- }
- handleHideDialog(false /* userCanceled */);
- }
-
- private void handleUserCanceled() {
- handleHideDialog(true /* userCanceled */);
- }
-
- private void handleTryAgainPressed() {
- try {
- mReceiver.onTryAgainPressed();
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException when handling try again", e);
- }
+ mCurrentDialog = null;
}
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- final boolean wasShowing = mDialogShowing;
// Save the state of the current dialog (buttons showing, etc)
- final Bundle savedState = new Bundle();
if (mCurrentDialog != null) {
+ final Bundle savedState = new Bundle();
mCurrentDialog.onSaveState(savedState);
- }
+ mCurrentDialog.dismissWithoutCallback(false /* animate */);
+ mCurrentDialog = null;
- if (mDialogShowing) {
- mCurrentDialog.forceRemove();
- mDialogShowing = false;
+ showDialog(mCurrentDialogArgs, true /* skipAnimation */, savedState);
}
+ }
- if (wasShowing) {
- handleShowDialog(mCurrentDialogArgs, true /* skipAnimation */, savedState);
- }
+ protected BiometricDialog buildDialog(Bundle biometricPromptBundle,
+ boolean requireConfirmation, int userId, int type, String opPackageName) {
+ return new BiometricDialogView.Builder(mContext)
+ .setCallback(this)
+ .setBiometricPromptBundle(biometricPromptBundle)
+ .setRequireConfirmation(requireConfirmation)
+ .setUserId(userId)
+ .setOpPackageName(opPackageName)
+ .build(type);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/DialogViewCallback.java b/packages/SystemUI/src/com/android/systemui/biometrics/DialogViewCallback.java
index 24fd22e..b65d1e8 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/DialogViewCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/DialogViewCallback.java
@@ -16,36 +16,38 @@
package com.android.systemui.biometrics;
+import android.annotation.IntDef;
+
/**
* Callback interface for dialog views. These should be implemented by the controller (e.g.
* FingerprintDialogImpl) and passed into their views (e.g. FingerprintDialogView).
*/
public interface DialogViewCallback {
- /**
- * Invoked when the user cancels authentication by tapping outside the prompt, etc. The dialog
- * should be dismissed.
- */
- void onUserCanceled();
+
+ int DISMISSED_USER_CANCELED = 1;
+ int DISMISSED_BUTTON_NEGATIVE = 2;
+ int DISMISSED_BUTTON_POSITIVE = 3;
+
+ int DISMISSED_AUTHENTICATED = 4;
+ int DISMISSED_ERROR = 5;
+ int DISMISSED_BY_SYSTEM_SERVER = 6;
+
+ @IntDef({DISMISSED_USER_CANCELED,
+ DISMISSED_BUTTON_NEGATIVE,
+ DISMISSED_BUTTON_POSITIVE,
+ DISMISSED_AUTHENTICATED,
+ DISMISSED_ERROR,
+ DISMISSED_BY_SYSTEM_SERVER})
+ @interface DismissedReason {}
/**
- * Invoked when an error is shown. The dialog should be dismissed after a set amount of time.
+ * Invoked when the dialog is dismissed
+ * @param reason
*/
- void onErrorShown();
+ void onDismissed(@DismissedReason int reason);
/**
- * Invoked when the negative button is pressed. The client should be notified and the dialog
- * should be dismissed.
- */
- void onNegativePressed();
-
- /**
- * Invoked when the positive button is pressed. The client should be notified and the dialog
- * should be dismissed.
- */
- void onPositivePressed();
-
- /**
- * Invoked when the "try again" button is pressed.
+ * Invoked when the "try again" button is clicked
*/
void onTryAgainPressed();
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/ui/BiometricDialogView.java
similarity index 70%
rename from packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
rename to packages/SystemUI/src/com/android/systemui/biometrics/ui/BiometricDialogView.java
index ce67577..2b4dde5 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/BiometricDialogView.java
@@ -11,10 +11,10 @@
* 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
+ * limitations under the License.
*/
-package com.android.systemui.biometrics;
+package com.android.systemui.biometrics.ui;
import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE;
@@ -23,6 +23,7 @@
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
+import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricPrompt;
import android.os.Binder;
import android.os.Bundle;
@@ -46,25 +47,30 @@
import android.widget.LinearLayout;
import android.widget.TextView;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.biometrics.BiometricDialog;
+import com.android.systemui.biometrics.DialogViewCallback;
+import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.util.leak.RotationUtils;
/**
* Abstract base class. Shows a dialog for BiometricPrompt.
*/
-public abstract class BiometricDialogView extends LinearLayout {
+public abstract class BiometricDialogView extends LinearLayout implements BiometricDialog {
private static final String TAG = "BiometricDialogView";
- private static final String KEY_TRY_AGAIN_VISIBILITY = "key_try_again_visibility";
- private static final String KEY_CONFIRM_VISIBILITY = "key_confirm_visibility";
- private static final String KEY_CONFIRM_ENABLED = "key_confirm_enabled";
- private static final String KEY_STATE = "key_state";
- private static final String KEY_ERROR_TEXT_VISIBILITY = "key_error_text_visibility";
- private static final String KEY_ERROR_TEXT_STRING = "key_error_text_string";
- private static final String KEY_ERROR_TEXT_IS_TEMPORARY = "key_error_text_is_temporary";
- private static final String KEY_ERROR_TEXT_COLOR = "key_error_text_color";
+ public static final String KEY_TRY_AGAIN_VISIBILITY = "key_try_again_visibility";
+ public static final String KEY_CONFIRM_VISIBILITY = "key_confirm_visibility";
+ public static final String KEY_CONFIRM_ENABLED = "key_confirm_enabled";
+ public static final String KEY_STATE = "key_state";
+ public static final String KEY_ERROR_TEXT_VISIBILITY = "key_error_text_visibility";
+ public static final String KEY_ERROR_TEXT_STRING = "key_error_text_string";
+ public static final String KEY_ERROR_TEXT_IS_TEMPORARY = "key_error_text_is_temporary";
+ public static final String KEY_ERROR_TEXT_COLOR = "key_error_text_color";
private static final int ANIMATION_DURATION_SHOW = 250; // ms
private static final int ANIMATION_DURATION_AWAY = 350; // ms
@@ -77,6 +83,8 @@
protected static final int STATE_PENDING_CONFIRMATION = 3;
protected static final int STATE_AUTHENTICATED = 4;
+ @VisibleForTesting
+ final WakefulnessLifecycle mWakefulnessLifecycle;
private final AccessibilityManager mAccessibilityManager;
private final IBinder mWindowToken = new Binder();
private final Interpolator mLinearOutSlowIn;
@@ -90,22 +98,30 @@
protected final ViewGroup mLayout;
protected final LinearLayout mDialog;
- protected final TextView mTitleText;
- protected final TextView mSubtitleText;
- protected final TextView mDescriptionText;
- protected final ImageView mBiometricIcon;
- protected final TextView mErrorText;
- protected final Button mPositiveButton;
- protected final Button mNegativeButton;
- protected final Button mTryAgainButton;
+ @VisibleForTesting
+ final TextView mTitleText;
+ @VisibleForTesting
+ final TextView mSubtitleText;
+ @VisibleForTesting
+ final TextView mDescriptionText;
+ @VisibleForTesting
+ final ImageView mBiometricIcon;
+ @VisibleForTesting
+ final TextView mErrorText;
+ @VisibleForTesting
+ final Button mPositiveButton;
+ @VisibleForTesting
+ final Button mNegativeButton;
+ @VisibleForTesting
+ final Button mTryAgainButton;
protected final int mTextColor;
private Bundle mBundle;
private Bundle mRestoredState;
+ private String mOpPackageName;
private int mState = STATE_IDLE;
- private boolean mAnimatingAway;
private boolean mWasForceRemoved;
private boolean mSkipIntro;
protected boolean mRequireConfirmation;
@@ -141,6 +157,15 @@
}
};
+ @VisibleForTesting
+ final WakefulnessLifecycle.Observer mWakefulnessObserver =
+ new WakefulnessLifecycle.Observer() {
+ @Override
+ public void onStartedGoingToSleep() {
+ animateAway(DialogViewCallback.DISMISSED_USER_CANCELED);
+ }
+ };
+
protected Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
@@ -155,8 +180,80 @@
}
};
- public BiometricDialogView(Context context, DialogViewCallback callback) {
+ /**
+ * Builds the dialog with specified parameters.
+ */
+ public static class Builder {
+ public static final int TYPE_FINGERPRINT = BiometricAuthenticator.TYPE_FINGERPRINT;
+ public static final int TYPE_FACE = BiometricAuthenticator.TYPE_FACE;
+
+ private Context mContext;
+ private DialogViewCallback mCallback;
+ private Bundle mBundle;
+ private boolean mRequireConfirmation;
+ private int mUserId;
+ private String mOpPackageName;
+
+ public Builder(Context context) {
+ mContext = context;
+ }
+
+ public Builder setCallback(DialogViewCallback callback) {
+ mCallback = callback;
+ return this;
+ }
+
+ public Builder setBiometricPromptBundle(Bundle bundle) {
+ mBundle = bundle;
+ return this;
+ }
+
+ public Builder setRequireConfirmation(boolean requireConfirmation) {
+ mRequireConfirmation = requireConfirmation;
+ return this;
+ }
+
+ public Builder setUserId(int userId) {
+ mUserId = userId;
+ return this;
+ }
+
+ public Builder setOpPackageName(String opPackageName) {
+ mOpPackageName = opPackageName;
+ return this;
+ }
+
+ public BiometricDialogView build(int type) {
+ return build(type, new Injector());
+ }
+
+ public BiometricDialogView build(int type, Injector injector) {
+ BiometricDialogView dialog;
+ if (type == TYPE_FINGERPRINT) {
+ dialog = new FingerprintDialogView(mContext, mCallback, injector);
+ } else if (type == TYPE_FACE) {
+ dialog = new FaceDialogView(mContext, mCallback, injector);
+ } else {
+ return null;
+ }
+ dialog.setBundle(mBundle);
+ dialog.setRequireConfirmation(mRequireConfirmation);
+ dialog.setUserId(mUserId);
+ dialog.setOpPackageName(mOpPackageName);
+ return dialog;
+ }
+ }
+
+ public static class Injector {
+ public WakefulnessLifecycle getWakefulnessLifecycle() {
+ return Dependency.get(WakefulnessLifecycle.class);
+ }
+ }
+
+ protected BiometricDialogView(Context context, DialogViewCallback callback, Injector injector) {
super(context);
+ mWakefulnessLifecycle = injector.getWakefulnessLifecycle();
+
mCallback = callback;
mLinearOutSlowIn = Interpolators.LINEAR_OUT_SLOW_IN;
mAccessibilityManager = mContext.getSystemService(AccessibilityManager.class);
@@ -178,19 +275,13 @@
addView(mLayout);
mLayout.setOnKeyListener(new View.OnKeyListener() {
- boolean downPressed = false;
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode != KeyEvent.KEYCODE_BACK) {
return false;
}
- if (event.getAction() == KeyEvent.ACTION_DOWN && downPressed == false) {
- downPressed = true;
- } else if (event.getAction() == KeyEvent.ACTION_DOWN) {
- downPressed = false;
- } else if (event.getAction() == KeyEvent.ACTION_UP && downPressed == true) {
- downPressed = false;
- mCallback.onUserCanceled();
+ if (event.getAction() == KeyEvent.ACTION_UP) {
+ animateAway(DialogViewCallback.DISMISSED_USER_CANCELED);
}
return true;
}
@@ -219,16 +310,16 @@
mNegativeButton.setOnClickListener((View v) -> {
if (mState == STATE_PENDING_CONFIRMATION || mState == STATE_AUTHENTICATED) {
- mCallback.onUserCanceled();
+ animateAway(DialogViewCallback.DISMISSED_USER_CANCELED);
} else {
- mCallback.onNegativePressed();
+ animateAway(DialogViewCallback.DISMISSED_BUTTON_NEGATIVE);
}
});
mPositiveButton.setOnClickListener((View v) -> {
updateState(STATE_AUTHENTICATED);
mHandler.postDelayed(() -> {
- mCallback.onPositivePressed();
+ animateAway(DialogViewCallback.DISMISSED_BUTTON_POSITIVE);
}, getDelayAfterAuthenticatedDurationMs());
});
@@ -248,21 +339,12 @@
mLayout.requestFocus();
}
- public void onSaveState(Bundle bundle) {
- bundle.putInt(KEY_TRY_AGAIN_VISIBILITY, mTryAgainButton.getVisibility());
- bundle.putInt(KEY_CONFIRM_VISIBILITY, mPositiveButton.getVisibility());
- bundle.putBoolean(KEY_CONFIRM_ENABLED, mPositiveButton.isEnabled());
- bundle.putInt(KEY_STATE, mState);
- bundle.putInt(KEY_ERROR_TEXT_VISIBILITY, mErrorText.getVisibility());
- bundle.putCharSequence(KEY_ERROR_TEXT_STRING, mErrorText.getText());
- bundle.putBoolean(KEY_ERROR_TEXT_IS_TEMPORARY, mHandler.hasMessages(MSG_RESET_MESSAGE));
- bundle.putInt(KEY_ERROR_TEXT_COLOR, mErrorText.getCurrentTextColor());
- }
-
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
+ mWakefulnessLifecycle.addObserver(mWakefulnessObserver);
+
final ImageView backgroundView = mLayout.findViewById(R.id.background);
if (mUserManager.isManagedProfile(mUserId)) {
@@ -278,6 +360,7 @@
}
mNegativeButton.setVisibility(View.VISIBLE);
+ mNegativeButton.setText(mBundle.getCharSequence(BiometricPrompt.KEY_NEGATIVE_TEXT));
if (RotationUtils.getRotation(mContext) != RotationUtils.ROTATION_NONE) {
mDialog.getLayoutParams().width = (int) mDialogWidth;
@@ -285,7 +368,6 @@
if (mRestoredState == null) {
updateState(STATE_AUTHENTICATING);
- mNegativeButton.setText(mBundle.getCharSequence(BiometricPrompt.KEY_NEGATIVE_TEXT));
final int hint = getHintStringResourceId();
if (hint != 0) {
mErrorText.setText(hint);
@@ -346,34 +428,49 @@
mSkipIntro = false;
}
+ @Override
+ public void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+
+ mWakefulnessLifecycle.removeObserver(mWakefulnessObserver);
+ }
+
private void setDismissesDialog(View v) {
v.setClickable(true);
v.setOnClickListener(v1 -> {
if (mState != STATE_AUTHENTICATED && shouldGrayAreaDismissDialog()) {
- mCallback.onUserCanceled();
+ animateAway(DialogViewCallback.DISMISSED_USER_CANCELED);
}
});
}
- public void startDismiss() {
+ private void animateAway(@DialogViewCallback.DismissedReason int reason) {
+ animateAway(true /* sendReason */, reason);
+ }
+
+ /**
+ * Animate the dialog away
+ * @param reason one of the {@link DialogViewCallback} codes
+ */
+ private void animateAway(boolean sendReason, @DialogViewCallback.DismissedReason int reason) {
if (!mCompletedAnimatingIn) {
Log.w(TAG, "startDismiss(): waiting for onDialogAnimatedIn");
mPendingDismissDialog = true;
return;
}
- mAnimatingAway = true;
-
// This is where final cleanup should occur.
final Runnable endActionRunnable = new Runnable() {
@Override
public void run() {
mWindowManager.removeView(BiometricDialogView.this);
- mAnimatingAway = false;
// Set the icons / text back to normal state
handleResetMessage();
showTryAgainButton(false /* show */);
updateState(STATE_IDLE);
+ if (sendReason) {
+ mCallback.onDismissed(reason);
+ }
}
};
@@ -398,47 +495,30 @@
}
/**
- * Force remove the window, cancelling any animation that's happening. This should only be
- * called if we want to quickly show the dialog again (e.g. on rotation). Calling this method
- * will cause the dialog to show without an animation the next time it's attached.
- */
- public void forceRemove() {
- mLayout.animate().cancel();
- mDialog.animate().cancel();
- mWindowManager.removeView(BiometricDialogView.this);
- mAnimatingAway = false;
- mWasForceRemoved = true;
- }
-
- /**
* Skip the intro animation
*/
- public void setSkipIntro(boolean skip) {
+ private void setSkipIntro(boolean skip) {
mSkipIntro = skip;
}
- public boolean isAnimatingAway() {
- return mAnimatingAway;
- }
-
- public void setBundle(Bundle bundle) {
+ private void setBundle(Bundle bundle) {
mBundle = bundle;
}
- public void setRequireConfirmation(boolean requireConfirmation) {
+ private void setRequireConfirmation(boolean requireConfirmation) {
mRequireConfirmation = requireConfirmation;
}
- public boolean requiresConfirmation() {
+ protected boolean requiresConfirmation() {
return mRequireConfirmation;
}
- public void setUserId(int userId) {
+ private void setUserId(int userId) {
mUserId = userId;
}
- public ViewGroup getLayout() {
- return mLayout;
+ private void setOpPackageName(String opPackageName) {
+ mOpPackageName = opPackageName;
}
// Shows an error/help message
@@ -452,17 +532,63 @@
BiometricPrompt.HIDE_DIALOG_DELAY);
}
+ @Override
+ public void show(WindowManager wm, boolean skipIntroAnimation) {
+ setSkipIntro(skipIntroAnimation);
+ wm.addView(this, getLayoutParams(mWindowToken));
+ }
+
+ /**
+ * Force remove the window, cancelling any animation that's happening. This should only be
+ * called if we want to quickly show the dialog again (e.g. on rotation). Calling this method
+ * will cause the dialog to show without an animation the next time it's attached.
+ */
+ @Override
+ public void dismissWithoutCallback(boolean animate) {
+ if (animate) {
+ animateAway(false /* sendReason */, 0 /* reason */);
+ } else {
+ mLayout.animate().cancel();
+ mDialog.animate().cancel();
+ mWindowManager.removeView(BiometricDialogView.this);
+ mWasForceRemoved = true;
+ }
+ }
+
+ @Override
+ public void dismissFromSystemServer() {
+ animateAway(DialogViewCallback.DISMISSED_BY_SYSTEM_SERVER);
+ }
+
+ @Override
+ public void onAuthenticationSucceeded() {
+ announceForAccessibility(getResources().getText(getAuthenticatedAccessibilityResourceId()));
+
+ if (requiresConfirmation()) {
+ updateState(STATE_PENDING_CONFIRMATION);
+ } else {
+ mHandler.postDelayed(() -> {
+ animateAway(DialogViewCallback.DISMISSED_AUTHENTICATED);
+ }, getDelayAfterAuthenticatedDurationMs());
+
+ updateState(STATE_AUTHENTICATED);
+ }
+ }
+
+
+ @Override
+ public void onAuthenticationFailed(String message) {
+ updateState(STATE_ERROR);
+ showTemporaryMessage(message);
+ }
+
/**
* Transient help message (acquire) is received, dialog stays showing. Sensor stays in
* "authenticating" state.
* @param message
*/
- public void onHelpReceived(String message) {
- updateState(STATE_ERROR);
- showTemporaryMessage(message);
- }
-
- public void onAuthenticationFailed(String message) {
+ @Override
+ public void onHelp(String message) {
updateState(STATE_ERROR);
showTemporaryMessage(message);
}
@@ -471,14 +597,61 @@
* Hard error is received, dialog will be dismissed soon.
* @param error
*/
- public void onErrorReceived(String error) {
+ @Override
+ public void onError(String error) {
updateState(STATE_ERROR);
showTemporaryMessage(error);
showTryAgainButton(false /* show */);
- mCallback.onErrorShown(); // TODO: Split between fp and face
+
+ mHandler.postDelayed(() -> {
+ animateAway(DialogViewCallback.DISMISSED_ERROR);
+ }, BiometricPrompt.HIDE_DIALOG_DELAY);
}
- public void updateState(int newState) {
+
+ @Override
+ public void onSaveState(Bundle bundle) {
+ bundle.putInt(KEY_TRY_AGAIN_VISIBILITY, mTryAgainButton.getVisibility());
+ bundle.putInt(KEY_CONFIRM_VISIBILITY, mPositiveButton.getVisibility());
+ bundle.putBoolean(KEY_CONFIRM_ENABLED, mPositiveButton.isEnabled());
+ bundle.putInt(KEY_STATE, mState);
+ bundle.putInt(KEY_ERROR_TEXT_VISIBILITY, mErrorText.getVisibility());
+ bundle.putCharSequence(KEY_ERROR_TEXT_STRING, mErrorText.getText());
+ bundle.putBoolean(KEY_ERROR_TEXT_IS_TEMPORARY, mHandler.hasMessages(MSG_RESET_MESSAGE));
+ bundle.putInt(KEY_ERROR_TEXT_COLOR, mErrorText.getCurrentTextColor());
+ }
+
+ @Override
+ public void restoreState(Bundle bundle) {
+ mRestoredState = bundle;
+ final int tryAgainVisibility = bundle.getInt(KEY_TRY_AGAIN_VISIBILITY);
+ mTryAgainButton.setVisibility(tryAgainVisibility);
+ final int confirmVisibility = bundle.getInt(KEY_CONFIRM_VISIBILITY);
+ mPositiveButton.setVisibility(confirmVisibility);
+ final boolean confirmEnabled = bundle.getBoolean(KEY_CONFIRM_ENABLED);
+ mPositiveButton.setEnabled(confirmEnabled);
+ mState = bundle.getInt(KEY_STATE);
+ mErrorText.setText(bundle.getCharSequence(KEY_ERROR_TEXT_STRING));
+ mErrorText.setContentDescription(bundle.getCharSequence(KEY_ERROR_TEXT_STRING));
+ final int errorTextVisibility = bundle.getInt(KEY_ERROR_TEXT_VISIBILITY);
+ mErrorText.setVisibility(errorTextVisibility);
+ if (errorTextVisibility == View.INVISIBLE || tryAgainVisibility == View.INVISIBLE
+ || confirmVisibility == View.INVISIBLE) {
+ announceAccessibilityEvent();
+ }
+ mErrorText.setTextColor(bundle.getInt(KEY_ERROR_TEXT_COLOR));
+ if (bundle.getBoolean(KEY_ERROR_TEXT_IS_TEMPORARY)) {
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_RESET_MESSAGE),
+ BiometricPrompt.HIDE_DIALOG_DELAY);
+ }
+ }
+
+ @Override
+ public String getOpPackageName() {
+ return mOpPackageName;
+ }
+
+ protected void updateState(int newState) {
if (newState == STATE_PENDING_CONFIRMATION) {
mHandler.removeMessages(MSG_RESET_MESSAGE);
mErrorText.setTextColor(mTextColor);
@@ -505,48 +678,24 @@
mState = newState;
}
- public void showTryAgainButton(boolean show) {
+ protected void showTryAgainButton(boolean show) {
}
- public void onDialogAnimatedIn() {
+ protected void onDialogAnimatedIn() {
mCompletedAnimatingIn = true;
if (mPendingDismissDialog) {
Log.d(TAG, "onDialogAnimatedIn(): mPendingDismissDialog=true, dismissing now");
- startDismiss();
+ animateAway(false /* sendReason */, 0);
mPendingDismissDialog = false;
}
}
- public void restoreState(Bundle bundle) {
- mRestoredState = bundle;
- final int tryAgainVisibility = bundle.getInt(KEY_TRY_AGAIN_VISIBILITY);
- mTryAgainButton.setVisibility(tryAgainVisibility);
- final int confirmVisibility = bundle.getInt(KEY_CONFIRM_VISIBILITY);
- mPositiveButton.setVisibility(confirmVisibility);
- final boolean confirmEnabled = bundle.getBoolean(KEY_CONFIRM_ENABLED);
- mPositiveButton.setEnabled(confirmEnabled);
- mState = bundle.getInt(KEY_STATE);
- mErrorText.setText(bundle.getCharSequence(KEY_ERROR_TEXT_STRING));
- mErrorText.setContentDescription(bundle.getCharSequence(KEY_ERROR_TEXT_STRING));
- final int errorTextVisibility = bundle.getInt(KEY_ERROR_TEXT_VISIBILITY);
- mErrorText.setVisibility(errorTextVisibility);
- if (errorTextVisibility == View.INVISIBLE || tryAgainVisibility == View.INVISIBLE
- || confirmVisibility == View.INVISIBLE) {
- announceAccessibilityEvent();
- }
- mErrorText.setTextColor(bundle.getInt(KEY_ERROR_TEXT_COLOR));
- if (bundle.getBoolean(KEY_ERROR_TEXT_IS_TEMPORARY)) {
- mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_RESET_MESSAGE),
- BiometricPrompt.HIDE_DIALOG_DELAY);
- }
- }
-
- protected int getState() {
- return mState;
- }
-
- public WindowManager.LayoutParams getLayoutParams() {
+ /**
+ * @param windowToken token for the window
+ * @return
+ */
+ public static WindowManager.LayoutParams getLayoutParams(IBinder windowToken) {
final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT,
@@ -555,7 +704,7 @@
PixelFormat.TRANSLUCENT);
lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
lp.setTitle("BiometricDialogView");
- lp.token = mWindowToken;
+ lp.token = windowToken;
return lp;
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/ui/FaceDialogView.java
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java
rename to packages/SystemUI/src/com/android/systemui/biometrics/ui/FaceDialogView.java
index ae6cb5c..bd87148 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/FaceDialogView.java
@@ -11,10 +11,10 @@
* 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
+ * limitations under the License.
*/
-package com.android.systemui.biometrics;
+package com.android.systemui.biometrics.ui;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -33,7 +33,9 @@
import android.view.View;
import android.view.ViewOutlineProvider;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
+import com.android.systemui.biometrics.DialogViewCallback;
/**
* This class loads the view for the system-provided dialog. The view consists of:
@@ -52,7 +54,8 @@
private static final int TEXT_ANIMATE_DISTANCE = 32; // dp
private static final int SIZE_UNKNOWN = 0;
- private static final int SIZE_SMALL = 1;
+ @VisibleForTesting
+ static final int SIZE_SMALL = 1;
private static final int SIZE_GROWING = 2;
private static final int SIZE_BIG = 3;
@@ -152,13 +155,13 @@
announceAccessibilityEvent();
};
- public FaceDialogView(Context context,
- DialogViewCallback callback) {
- super(context, callback);
+ protected FaceDialogView(Context context, DialogViewCallback callback, Injector injector) {
+ super(context, callback, injector);
mIconController = new IconController();
}
- private void updateSize(int newSize) {
+ @VisibleForTesting
+ void updateSize(int newSize) {
final float padding = dpToPixels(IMPLICIT_Y_PADDING);
final float iconSmallPositionY = mDialog.getHeight() - mBiometricIcon.getHeight() - padding;
@@ -339,8 +342,8 @@
}
@Override
- public void onErrorReceived(String error) {
- super.onErrorReceived(error);
+ public void onError(String error) {
+ super.onError(error);
// All error messages will cause the dialog to go from small -> big. Error messages
// are messages such as lockout, auth failed, etc.
if (mSize == SIZE_SMALL) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/FingerprintDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/ui/FingerprintDialogView.java
similarity index 93%
rename from packages/SystemUI/src/com/android/systemui/biometrics/FingerprintDialogView.java
rename to packages/SystemUI/src/com/android/systemui/biometrics/ui/FingerprintDialogView.java
index 183933e..e597080 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/FingerprintDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/FingerprintDialogView.java
@@ -11,10 +11,10 @@
* 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
+ * limitations under the License.
*/
-package com.android.systemui.biometrics;
+package com.android.systemui.biometrics.ui;
import android.content.Context;
import android.graphics.drawable.AnimatedVectorDrawable;
@@ -22,6 +22,7 @@
import android.util.Log;
import com.android.systemui.R;
+import com.android.systemui.biometrics.DialogViewCallback;
/**
* This class loads the view for the system-provided dialog. The view consists of:
@@ -32,9 +33,9 @@
private static final String TAG = "FingerprintDialogView";
- public FingerprintDialogView(Context context,
- DialogViewCallback callback) {
- super(context, callback);
+ protected FingerprintDialogView(Context context, DialogViewCallback callback,
+ Injector injector) {
+ super(context, callback, injector);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
new file mode 100644
index 0000000..f0e8c16
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
@@ -0,0 +1,156 @@
+/*
+ * 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.broadcast
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.IntentFilter
+import android.os.Handler
+import android.os.Looper
+import android.os.Message
+import android.os.UserHandle
+import android.util.Log
+import android.util.SparseArray
+import com.android.internal.annotations.VisibleForTesting
+import com.android.systemui.Dependency.BG_LOOPER_NAME
+import com.android.systemui.Dependency.MAIN_HANDLER_NAME
+import com.android.systemui.Dumpable
+import java.io.FileDescriptor
+import java.io.PrintWriter
+import javax.inject.Inject
+import javax.inject.Named
+import javax.inject.Singleton
+
+data class ReceiverData(
+ val receiver: BroadcastReceiver,
+ val filter: IntentFilter,
+ val handler: Handler,
+ val user: UserHandle
+)
+
+private const val MSG_ADD_RECEIVER = 0
+private const val MSG_REMOVE_RECEIVER = 1
+private const val MSG_REMOVE_RECEIVER_FOR_USER = 2
+private const val TAG = "BroadcastDispatcher"
+private const val DEBUG = false
+
+/**
+ * SystemUI master Broadcast Dispatcher.
+ *
+ * This class allows [BroadcastReceiver] to register and centralizes registrations to [Context]
+ * from SystemUI. That way the number of calls to [BroadcastReceiver.onReceive] can be reduced for
+ * a given broadcast.
+ *
+ * Use only for IntentFilters with actions and optionally categories. It does not support,
+ * permissions, schemes or data types. Cannot be used for getting sticky broadcasts.
+ */
+@Singleton
+open class BroadcastDispatcher @Inject constructor (
+ private val context: Context,
+ @Named(MAIN_HANDLER_NAME) private val mainHandler: Handler,
+ @Named(BG_LOOPER_NAME) private val bgLooper: Looper
+) : Dumpable {
+
+ // Only modify in BG thread
+ private val receiversByUser = SparseArray<UserBroadcastDispatcher>(20)
+
+ /**
+ * Register a receiver for broadcast with the dispatcher
+ *
+ * @param receiver A receiver to dispatch the [Intent]
+ * @param filter A filter to determine what broadcasts should be dispatched to this receiver.
+ * It will only take into account actions and categories for filtering.
+ * @param handler A handler to dispatch [BroadcastReceiver.onReceive]. By default, it is the
+ * main handler.
+ * @param user A user handle to determine which broadcast should be dispatched to this receiver.
+ * By default, it is the current user.
+ */
+ @JvmOverloads
+ fun registerReceiver(
+ receiver: BroadcastReceiver,
+ filter: IntentFilter,
+ handler: Handler = mainHandler,
+ user: UserHandle = context.user
+ ) {
+ this.handler.obtainMessage(MSG_ADD_RECEIVER, ReceiverData(receiver, filter, handler, user))
+ .sendToTarget()
+ }
+
+ /**
+ * Unregister receiver for all users.
+ * <br>
+ * This will remove every registration of [receiver], not those done just with [UserHandle.ALL].
+ *
+ * @param receiver The receiver to unregister. It will be unregistered for all users.
+ */
+ fun unregisterReceiver(receiver: BroadcastReceiver) {
+ handler.obtainMessage(MSG_REMOVE_RECEIVER, receiver).sendToTarget()
+ }
+
+ /**
+ * Unregister receiver for a particular user.
+ *
+ * @param receiver The receiver to unregister. It will be unregistered for all users.
+ * @param user The user associated to the registered [receiver]. It can be [UserHandle.ALL].
+ */
+ fun unregisterReceiverForUser(receiver: BroadcastReceiver, user: UserHandle) {
+ handler.obtainMessage(MSG_REMOVE_RECEIVER_FOR_USER, user.identifier, 0, receiver)
+ .sendToTarget()
+ }
+
+ @VisibleForTesting
+ protected open fun createUBRForUser(userId: Int) =
+ UserBroadcastDispatcher(context, userId, mainHandler, bgLooper)
+
+ override fun dump(fd: FileDescriptor?, pw: PrintWriter?, args: Array<out String>?) {
+ pw?.println("Broadcast dispatcher:")
+ for (index in 0 until receiversByUser.size()) {
+ pw?.println(" User ${receiversByUser.keyAt(index)}")
+ receiversByUser.valueAt(index).dump(fd, pw, args)
+ }
+ }
+
+ private val handler = object : Handler(bgLooper) {
+ override fun handleMessage(msg: Message) {
+ when (msg.what) {
+ MSG_ADD_RECEIVER -> {
+ val data = msg.obj as ReceiverData
+ val userId = data.user.identifier
+ if (userId < UserHandle.USER_ALL) {
+ if (DEBUG) Log.w(TAG, "Register receiver for invalid user: $userId")
+ return
+ }
+ val uBR = receiversByUser.get(userId, createUBRForUser(userId))
+ receiversByUser.put(userId, uBR)
+ uBR.registerReceiver(data)
+ }
+
+ MSG_REMOVE_RECEIVER -> {
+ for (it in 0 until receiversByUser.size()) {
+ receiversByUser.valueAt(it).unregisterReceiver(msg.obj as BroadcastReceiver)
+ }
+ }
+
+ MSG_REMOVE_RECEIVER_FOR_USER -> {
+ receiversByUser.get(msg.arg1)?.unregisterReceiver(msg.obj as BroadcastReceiver)
+ }
+
+ else -> super.handleMessage(msg)
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt b/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt
new file mode 100644
index 0000000..d44b63e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt
@@ -0,0 +1,179 @@
+/*
+ * 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.broadcast
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.os.Handler
+import android.os.Looper
+import android.os.Message
+import android.os.UserHandle
+import android.util.ArrayMap
+import android.util.ArraySet
+import android.util.Log
+import com.android.systemui.Dumpable
+import java.io.FileDescriptor
+import java.io.PrintWriter
+import java.util.concurrent.atomic.AtomicBoolean
+
+private const val MSG_REGISTER_RECEIVER = 0
+private const val MSG_UNREGISTER_RECEIVER = 1
+private const val TAG = "UniversalReceiver"
+private const val DEBUG = false
+
+/**
+ * Broadcast dispatcher for a given user registration [userId].
+ *
+ * Created by [BroadcastDispatcher] as needed by users. The value of [userId] can be
+ * [UserHandle.USER_ALL].
+ */
+class UserBroadcastDispatcher(
+ private val context: Context,
+ private val userId: Int,
+ private val mainHandler: Handler,
+ private val bgLooper: Looper
+) : BroadcastReceiver(), Dumpable {
+
+ private val bgHandler = object : Handler(bgLooper) {
+ override fun handleMessage(msg: Message) {
+ when (msg.what) {
+ MSG_REGISTER_RECEIVER -> handleRegisterReceiver(msg.obj as ReceiverData)
+ MSG_UNREGISTER_RECEIVER -> handleUnregisterReceiver(msg.obj as BroadcastReceiver)
+ else -> Unit
+ }
+ }
+ }
+
+ private val registered = AtomicBoolean(false)
+
+ internal fun isRegistered() = registered.get()
+
+ private val registerReceiver = Runnable {
+ val categories = mutableSetOf<String>()
+ receiverToReceiverData.values.flatten().forEach {
+ it.filter.categoriesIterator()?.asSequence()?.let {
+ categories.addAll(it)
+ }
+ }
+ val intentFilter = IntentFilter().apply {
+ actionsToReceivers.keys.forEach { addAction(it) }
+ categories.forEach { addCategory(it) }
+ }
+
+ if (registered.get()) {
+ context.unregisterReceiver(this)
+ registered.set(false)
+ }
+ // Short interval without receiver, this can be problematic
+ if (intentFilter.countActions() > 0 && !registered.get()) {
+ context.registerReceiverAsUser(
+ this,
+ UserHandle.of(userId),
+ intentFilter,
+ null,
+ bgHandler)
+ registered.set(true)
+ }
+ }
+
+ // Only modify in BG thread
+ private val actionsToReceivers = ArrayMap<String, MutableSet<ReceiverData>>()
+ private val receiverToReceiverData = ArrayMap<BroadcastReceiver, MutableSet<ReceiverData>>()
+
+ override fun onReceive(context: Context, intent: Intent) {
+ bgHandler.post(HandleBroadcastRunnable(actionsToReceivers, context, intent))
+ }
+
+ /**
+ * Register a [ReceiverData] for this user.
+ */
+ fun registerReceiver(receiverData: ReceiverData) {
+ bgHandler.obtainMessage(MSG_REGISTER_RECEIVER, receiverData).sendToTarget()
+ }
+
+ /**
+ * Unregister a given [BroadcastReceiver] for this user.
+ */
+ fun unregisterReceiver(receiver: BroadcastReceiver) {
+ bgHandler.obtainMessage(MSG_UNREGISTER_RECEIVER, receiver).sendToTarget()
+ }
+
+ private fun handleRegisterReceiver(receiverData: ReceiverData) {
+ if (DEBUG) Log.w(TAG, "Register receiver: ${receiverData.receiver}")
+ receiverToReceiverData.getOrPut(receiverData.receiver, { ArraySet() }).add(receiverData)
+ var changed = false
+ // Index the BroadcastReceiver by all its actions, that way it's easier to dispatch given
+ // a received intent.
+ receiverData.filter.actionsIterator().forEach {
+ actionsToReceivers.getOrPut(it) {
+ changed = true
+ ArraySet()
+ }.add(receiverData)
+ }
+ if (changed) {
+ mainHandler.post(registerReceiver)
+ }
+ }
+
+ private fun handleUnregisterReceiver(receiver: BroadcastReceiver) {
+ if (DEBUG) Log.w(TAG, "Unregister receiver: $receiver")
+ val actions = receiverToReceiverData.getOrElse(receiver) { return }
+ .flatMap { it.filter.actionsIterator().asSequence().asIterable() }.toSet()
+ receiverToReceiverData.get(receiver)?.clear()
+ var changed = false
+ actions.forEach { action ->
+ actionsToReceivers.get(action)?.removeIf { it.receiver == receiver }
+ if (actionsToReceivers.get(action)?.isEmpty() ?: false) {
+ changed = true
+ actionsToReceivers.remove(action)
+ }
+ }
+ if (changed) {
+ mainHandler.post(registerReceiver)
+ }
+ }
+
+ override fun dump(fd: FileDescriptor?, pw: PrintWriter?, args: Array<out String>?) {
+ pw?.println(" Registered=${registered.get()}")
+ actionsToReceivers.forEach { (action, list) ->
+ pw?.println(" $action:")
+ list.forEach { pw?.println(" ${it.receiver}") }
+ }
+ }
+
+ private class HandleBroadcastRunnable(
+ val actionsToReceivers: Map<String, Set<ReceiverData>>,
+ val context: Context,
+ val intent: Intent
+ ) : Runnable {
+ override fun run() {
+ if (DEBUG) Log.w(TAG, "Dispatching $intent")
+ actionsToReceivers.get(intent.action)
+ ?.filter {
+ it.filter.hasAction(intent.action) &&
+ it.filter.matchCategories(intent.categories) == null }
+ ?.forEach {
+ it.handler.post {
+ if (DEBUG) Log.w(TAG, "Dispatching to ${it.receiver}")
+ it.receiver.onReceive(context, intent)
+ }
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java
index c58b7db..82ae30a 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java
@@ -39,8 +39,8 @@
// most swipes will follow somewhat of a 'C' or 'S' shape, we allow more deviance along the
// `SECONDARY` axis.
private static final float MAX_X_PRIMARY_DEVIANCE = .05f;
- private static final float MAX_Y_PRIMARY_DEVIANCE = .05f;
- private static final float MAX_X_SECONDARY_DEVIANCE = .3f;
+ private static final float MAX_Y_PRIMARY_DEVIANCE = .1f;
+ private static final float MAX_X_SECONDARY_DEVIANCE = .6f;
private static final float MAX_Y_SECONDARY_DEVIANCE = .3f;
private final float mMaxXPrimaryDeviance;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index 991d9fa..0403a05 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -248,7 +248,9 @@
int numPages = Math.max(nTiles / mPages.get(0).maxTiles(), 1);
// Add one more not full page if needed
- numPages += (nTiles % mPages.get(0).maxTiles() == 0 ? 0 : 1);
+ if (nTiles > numPages * mPages.get(0).maxTiles()) {
+ numPages++;
+ }
final int NP = mPages.size();
for (int i = 0; i < NP; i++) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index 001e094..16a3975 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -73,6 +73,7 @@
if (listening) {
refreshState();
}
+ mHotspotController.handleSetListening(listening);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index fa0fe13..134d4b8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -271,7 +271,7 @@
default void onRotationProposal(int rotation, boolean isValid) { }
default void showBiometricDialog(Bundle bundle, IBiometricServiceReceiverInternal receiver,
- int type, boolean requireConfirmation, int userId) { }
+ int type, boolean requireConfirmation, int userId, String opPackageName) { }
default void onBiometricAuthenticated(boolean authenticated, String failureReason) { }
default void onBiometricHelp(String message) { }
default void onBiometricError(String error) { }
@@ -741,7 +741,7 @@
@Override
public void showBiometricDialog(Bundle bundle, IBiometricServiceReceiverInternal receiver,
- int type, boolean requireConfirmation, int userId) {
+ int type, boolean requireConfirmation, int userId, String opPackageName) {
synchronized (mLock) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = bundle;
@@ -749,6 +749,7 @@
args.argi1 = type;
args.arg3 = requireConfirmation;
args.argi2 = userId;
+ args.arg4 = opPackageName;
mHandler.obtainMessage(MSG_BIOMETRIC_SHOW, args)
.sendToTarget();
}
@@ -1036,7 +1037,8 @@
(IBiometricServiceReceiverInternal) someArgs.arg2,
someArgs.argi1 /* type */,
(boolean) someArgs.arg3 /* requireConfirmation */,
- someArgs.argi2 /* userId */);
+ someArgs.argi2 /* userId */,
+ (String) someArgs.arg4 /* opPackageName */);
}
someArgs.recycle();
break;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
index 48d6de9..276afa7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
@@ -41,7 +41,6 @@
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.phone.ShadeController
-import com.android.systemui.statusbar.policy.HeadsUpManager
import javax.inject.Inject
import javax.inject.Singleton
@@ -52,11 +51,13 @@
*/
@Singleton
class PulseExpansionHandler @Inject
-constructor(context: Context,
- private val wakeUpCoordinator: NotificationWakeUpCoordinator,
- private val bypassController: KeyguardBypassController,
- private val headsUpManager: HeadsUpManagerPhone,
- private val roundnessManager: NotificationRoundnessManager) : Gefingerpoken {
+constructor(
+ context: Context,
+ private val wakeUpCoordinator: NotificationWakeUpCoordinator,
+ private val bypassController: KeyguardBypassController,
+ private val headsUpManager: HeadsUpManagerPhone,
+ private val roundnessManager: NotificationRoundnessManager
+) : Gefingerpoken {
companion object {
private val RUBBERBAND_FACTOR_STATIC = 0.25f
private val SPRING_BACK_ANIMATION_LENGTH_MS = 375
@@ -124,8 +125,8 @@
}
private fun maybeStartExpansion(event: MotionEvent): Boolean {
- if (!wakeUpCoordinator.canShowPulsingHuns || qsExpanded
- || bouncerShowing) {
+ if (!wakeUpCoordinator.canShowPulsingHuns || qsExpanded ||
+ bouncerShowing) {
return false
}
if (velocityTracker == null) {
@@ -160,18 +161,18 @@
}
MotionEvent.ACTION_UP -> {
- recycleVelocityTracker();
+ recycleVelocityTracker()
}
MotionEvent.ACTION_CANCEL -> {
- recycleVelocityTracker();
+ recycleVelocityTracker()
}
}
return false
}
private fun recycleVelocityTracker() {
- velocityTracker?.recycle();
+ velocityTracker?.recycle()
velocityTracker = null
}
@@ -216,7 +217,7 @@
"com.android.systemui:PULSEDRAG")
}
shadeController.goToLockedShade(mStartingChild)
- leavingLockscreen = true;
+ leavingLockscreen = true
isExpanding = false
if (mStartingChild is ExpandableNotificationRow) {
val row = mStartingChild as ExpandableNotificationRow?
@@ -227,7 +228,7 @@
private fun updateExpansionHeight(height: Float) {
var expansionHeight = max(height, 0.0f)
if (!mReachedWakeUpHeight && height > mWakeUpHeight) {
- mReachedWakeUpHeight = true;
+ mReachedWakeUpHeight = true
}
if (mStartingChild != null) {
val child = mStartingChild!!
@@ -317,9 +318,11 @@
} else null
}
- fun setUp(stackScroller: NotificationStackScrollLayout,
- expansionCallback: ExpansionCallback,
- shadeController: ShadeController) {
+ fun setUp(
+ stackScroller: NotificationStackScrollLayout,
+ expansionCallback: ExpansionCallback,
+ shadeController: ShadeController
+ ) {
this.expansionCallback = expansionCallback
this.shadeController = shadeController
this.stackScroller = stackScroller
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index fdee278..3485f23 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.phone;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
+
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
@@ -955,7 +957,8 @@
}
public void showPinningEscapeToast() {
- mScreenPinningNotify.showEscapeToast(isRecentsButtonVisible());
+ mScreenPinningNotify.showEscapeToast(
+ mNavBarMode == NAV_BAR_MODE_GESTURAL, isRecentsButtonVisible());
}
public boolean isVertical() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScreenPinningNotify.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScreenPinningNotify.java
index f8731b4..071e00d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScreenPinningNotify.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScreenPinningNotify.java
@@ -51,7 +51,7 @@
}
/** Show a toast that describes the gesture the user should use to escape pinned mode. */
- public void showEscapeToast(boolean isRecentsButtonVisible) {
+ public void showEscapeToast(boolean isGestureNavEnabled, boolean isRecentsButtonVisible) {
long showToastTime = SystemClock.elapsedRealtime();
if ((showToastTime - mLastShowToastTime) < SHOW_TOAST_MINIMUM_INTERVAL) {
Slog.i(TAG, "Ignore toast since it is requested in very short interval.");
@@ -60,9 +60,11 @@
if (mLastToast != null) {
mLastToast.cancel();
}
- mLastToast = makeAllUserToastAndShow(isRecentsButtonVisible
- ? R.string.screen_pinning_toast
- : R.string.screen_pinning_toast_recents_invisible);
+ mLastToast = makeAllUserToastAndShow(isGestureNavEnabled
+ ? R.string.screen_pinning_toast_gesture_nav
+ : isRecentsButtonVisible
+ ? R.string.screen_pinning_toast
+ : R.string.screen_pinning_toast_recents_invisible);
mLastShowToastTime = showToastTime;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
index 830b50e..8b06a9f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
@@ -20,6 +20,8 @@
import com.android.systemui.statusbar.policy.HotspotController.Callback;
public interface HotspotController extends CallbackController<Callback>, Dumpable {
+ void handleSetListening(boolean listening);
+
boolean isHotspotEnabled();
boolean isHotspotTransient();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
index db2be0e..1c6d12f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
@@ -51,6 +51,7 @@
private int mHotspotState;
private int mNumConnectedDevices;
private boolean mWaitingForTerminalState;
+ private boolean mListening;
/**
*/
@@ -105,14 +106,18 @@
if (DEBUG) Log.d(TAG, "addCallback " + callback);
mCallbacks.add(callback);
if (mWifiManager != null) {
- if (mCallbacks.size() == 1) {
- mWifiManager.registerSoftApCallback(this, mMainHandler);
- } else {
- // mWifiManager#registerSoftApCallback triggers a call to onNumClientsChanged
- // on the Main Handler. In order to always update the callback on added, we
- // make this call when adding callbacks after the first.
- mMainHandler.post(() ->
- callback.onHotspotChanged(isHotspotEnabled(), mNumConnectedDevices));
+ if (mListening) {
+ if (mCallbacks.size() == 1) {
+ mWifiManager.registerSoftApCallback(this, mMainHandler);
+ } else {
+ // mWifiManager#registerSoftApCallback triggers a call to
+ // onNumClientsChanged on the Main Handler. In order to always update the
+ // callback on added, we make this call when adding callbacks after the
+ // first.
+ mMainHandler.post(() ->
+ callback.onHotspotChanged(isHotspotEnabled(),
+ mNumConnectedDevices));
+ }
}
}
}
@@ -124,13 +129,24 @@
if (DEBUG) Log.d(TAG, "removeCallback " + callback);
synchronized (mCallbacks) {
mCallbacks.remove(callback);
- if (mCallbacks.isEmpty() && mWifiManager != null) {
+ if (mCallbacks.isEmpty() && mWifiManager != null && mListening) {
mWifiManager.unregisterSoftApCallback(this);
}
}
}
@Override
+ public void handleSetListening(boolean listening) {
+ // Wait for the first |handleSetListening(true))| to register softap callbacks (for lazy
+ // registration of the softap callbacks).
+ if (mListening || !listening) return;
+ mListening = true;
+ if (mCallbacks.size() >= 1) {
+ mWifiManager.registerSoftApCallback(this, mMainHandler);
+ }
+ }
+
+ @Override
public boolean isHotspotEnabled() {
return mHotspotState == WifiManager.WIFI_AP_STATE_ENABLED;
}
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 e75365e..7acf4fd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -537,8 +537,14 @@
return mConfig.nr5GIconMap.get(Config.NR_CONNECTED);
}
} else if (nrState == NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED) {
- if (mConfig.nr5GIconMap.containsKey(Config.NR_NOT_RESTRICTED)) {
- return mConfig.nr5GIconMap.get(Config.NR_NOT_RESTRICTED);
+ if (mCurrentState.activityDormant) {
+ if (mConfig.nr5GIconMap.containsKey(Config.NR_NOT_RESTRICTED_RRC_IDLE)) {
+ return mConfig.nr5GIconMap.get(Config.NR_NOT_RESTRICTED_RRC_IDLE);
+ }
+ } else {
+ if (mConfig.nr5GIconMap.containsKey(Config.NR_NOT_RESTRICTED_RRC_CON)) {
+ return mConfig.nr5GIconMap.get(Config.NR_NOT_RESTRICTED_RRC_CON);
+ }
}
} else if (nrState == NetworkRegistrationInfo.NR_STATE_RESTRICTED) {
if (mConfig.nr5GIconMap.containsKey(Config.NR_RESTRICTED)) {
@@ -559,6 +565,8 @@
|| activity == TelephonyManager.DATA_ACTIVITY_IN;
mCurrentState.activityOut = activity == TelephonyManager.DATA_ACTIVITY_INOUT
|| activity == TelephonyManager.DATA_ACTIVITY_OUT;
+ mCurrentState.activityDormant = activity == TelephonyManager.DATA_ACTIVITY_DORMANT;
+
notifyListenersIfNecessary();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 1c24bb9..292571e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -312,6 +312,7 @@
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
filter.addAction(ConnectivityManager.INET_CONDITION_ACTION);
filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+ filter.addAction(Intent.ACTION_BOOT_COMPLETED);
filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
mContext.registerReceiver(this, filter, null, mReceiverHandler);
mListening = true;
@@ -513,6 +514,9 @@
recalculateEmergency();
}
break;
+ case Intent.ACTION_BOOT_COMPLETED:
+ mWifiSignalController.handleBootCompleted();
+ break;
case CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED:
mConfig = Config.readConfig(mContext);
mReceiverHandler.post(this::handleConfigurationChanged);
@@ -1108,8 +1112,9 @@
static class Config {
static final int NR_CONNECTED_MMWAVE = 1;
static final int NR_CONNECTED = 2;
- static final int NR_NOT_RESTRICTED = 3;
- static final int NR_RESTRICTED = 4;
+ static final int NR_NOT_RESTRICTED_RRC_IDLE = 3;
+ static final int NR_NOT_RESTRICTED_RRC_CON = 4;
+ static final int NR_RESTRICTED = 5;
Map<Integer, MobileIconGroup> nr5GIconMap = new HashMap<>();
@@ -1129,10 +1134,11 @@
*/
private static final Map<String, Integer> NR_STATUS_STRING_TO_INDEX;
static {
- NR_STATUS_STRING_TO_INDEX = new HashMap<>(4);
+ NR_STATUS_STRING_TO_INDEX = new HashMap<>(5);
NR_STATUS_STRING_TO_INDEX.put("connected_mmwave", NR_CONNECTED_MMWAVE);
NR_STATUS_STRING_TO_INDEX.put("connected", NR_CONNECTED);
- NR_STATUS_STRING_TO_INDEX.put("not_restricted", NR_NOT_RESTRICTED);
+ NR_STATUS_STRING_TO_INDEX.put("not_restricted_rrc_idle", NR_NOT_RESTRICTED_RRC_IDLE);
+ NR_STATUS_STRING_TO_INDEX.put("not_restricted_rrc_con", NR_NOT_RESTRICTED_RRC_CON);
NR_STATUS_STRING_TO_INDEX.put("restricted", NR_RESTRICTED);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java
index 9ec30d4..abe3f2c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java
@@ -258,6 +258,7 @@
boolean enabled;
boolean activityIn;
boolean activityOut;
+ public boolean activityDormant;
int level;
IconGroup iconGroup;
int inetCondition;
@@ -274,6 +275,7 @@
inetCondition = state.inetCondition;
activityIn = state.activityIn;
activityOut = state.activityOut;
+ activityDormant = state.activityDormant;
rssi = state.rssi;
time = state.time;
}
@@ -297,6 +299,7 @@
.append("iconGroup=").append(iconGroup).append(',')
.append("activityIn=").append(activityIn).append(',')
.append("activityOut=").append(activityOut).append(',')
+ .append("activityDormant=").append(activityDormant).append(',')
.append("rssi=").append(rssi).append(',')
.append("lastModified=").append(DateFormat.format("MM-dd HH:mm:ss", time));
}
@@ -314,6 +317,7 @@
&& other.iconGroup == iconGroup
&& other.activityIn == activityIn
&& other.activityOut == activityOut
+ && other.activityDormant == activityDormant
&& other.rssi == rssi;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
index 6f63544..a441f66 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
@@ -38,6 +38,7 @@
public class WifiSignalController extends
SignalController<WifiSignalController.WifiState, SignalController.IconGroup> {
private final boolean mHasMobileData;
+ private final WifiManager mWifiManager;
private final WifiStatusTracker mWifiTracker;
public WifiSignalController(Context context, boolean hasMobileData,
@@ -49,13 +50,11 @@
context.getSystemService(NetworkScoreManager.class);
ConnectivityManager connectivityManager =
context.getSystemService(ConnectivityManager.class);
+ mWifiManager = wifiManager;
mWifiTracker = new WifiStatusTracker(mContext, wifiManager, networkScoreManager,
connectivityManager, this::handleStatusUpdated);
mWifiTracker.setListening(true);
mHasMobileData = hasMobileData;
- if (wifiManager != null) {
- wifiManager.registerTrafficStateCallback(new WifiTrafficStateCallback(), null);
- }
// WiFi only has one state.
mCurrentState.iconGroup = mLastState.iconGroup = new IconGroup(
"Wi-Fi Icons",
@@ -128,6 +127,10 @@
notifyListenersIfNecessary();
}
+ public void handleBootCompleted() {
+ mWifiManager.registerTrafficStateCallback(new WifiTrafficStateCallback(), null);
+ }
+
/**
* Handler to receive the data activity on wifi.
*/
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricDialogImplTest.java
new file mode 100644
index 0000000..8f2f8b1
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricDialogImplTest.java
@@ -0,0 +1,329 @@
+/*
+ * 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.biometrics;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.TestCase.assertNotNull;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManager;
+import android.app.IActivityTaskManager;
+import android.content.ComponentName;
+import android.content.pm.PackageManager;
+import android.content.res.Configuration;
+import android.hardware.biometrics.BiometricPrompt;
+import android.hardware.biometrics.IBiometricServiceReceiverInternal;
+import android.os.Bundle;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableContext;
+import android.testing.TestableLooper.RunWithLooper;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.phone.StatusBar;
+
+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 java.util.ArrayList;
+import java.util.List;
+
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+@SmallTest
+public class BiometricDialogImplTest extends SysuiTestCase {
+
+ @Mock
+ private PackageManager mPackageManager;
+ @Mock
+ private IBiometricServiceReceiverInternal mReceiver;
+ @Mock
+ private BiometricDialog mDialog1;
+ @Mock
+ private BiometricDialog mDialog2;
+
+ private TestableBiometricDialogImpl mBiometricDialogImpl;
+
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+
+ TestableContext context = spy(mContext);
+
+ mContext.putComponent(StatusBar.class, mock(StatusBar.class));
+ mContext.putComponent(CommandQueue.class, mock(CommandQueue.class));
+
+ when(context.getPackageManager()).thenReturn(mPackageManager);
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE))
+ .thenReturn(true);
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT))
+ .thenReturn(true);
+
+ when(mDialog1.getOpPackageName()).thenReturn("Dialog1");
+ when(mDialog2.getOpPackageName()).thenReturn("Dialog2");
+
+ mBiometricDialogImpl = new TestableBiometricDialogImpl(new MockInjector());
+ mBiometricDialogImpl.mContext = context;
+ mBiometricDialogImpl.mComponents = mContext.getComponents();
+
+ mBiometricDialogImpl.start();
+ }
+
+ // Callback tests
+
+ @Test
+ public void testSendsReasonUserCanceled_whenDismissedByUserCancel() throws Exception {
+ showDialog(BiometricPrompt.TYPE_FACE);
+ mBiometricDialogImpl.onDismissed(DialogViewCallback.DISMISSED_USER_CANCELED);
+ verify(mReceiver).onDialogDismissed(BiometricPrompt.DISMISSED_REASON_USER_CANCEL);
+ }
+
+ @Test
+ public void testSendsReasonNegative_whenDismissedByButtonNegative() throws Exception {
+ showDialog(BiometricPrompt.TYPE_FACE);
+ mBiometricDialogImpl.onDismissed(DialogViewCallback.DISMISSED_BUTTON_NEGATIVE);
+ verify(mReceiver).onDialogDismissed(BiometricPrompt.DISMISSED_REASON_NEGATIVE);
+ }
+
+ @Test
+ public void testSendsReasonConfirmed_whenDismissedByButtonPositive() throws Exception {
+ showDialog(BiometricPrompt.TYPE_FACE);
+ mBiometricDialogImpl.onDismissed(DialogViewCallback.DISMISSED_BUTTON_POSITIVE);
+ verify(mReceiver).onDialogDismissed(BiometricPrompt.DISMISSED_REASON_CONFIRMED);
+ }
+
+ @Test
+ public void testSendsReasonConfirmNotRequired_whenDismissedByAuthenticated() throws Exception {
+ showDialog(BiometricPrompt.TYPE_FACE);
+ mBiometricDialogImpl.onDismissed(DialogViewCallback.DISMISSED_AUTHENTICATED);
+ verify(mReceiver).onDialogDismissed(BiometricPrompt.DISMISSED_REASON_CONFIRM_NOT_REQUIRED);
+ }
+
+ @Test
+ public void testSendsReasonError_whenDismissedByError() throws Exception {
+ showDialog(BiometricPrompt.TYPE_FACE);
+ mBiometricDialogImpl.onDismissed(DialogViewCallback.DISMISSED_ERROR);
+ verify(mReceiver).onDialogDismissed(BiometricPrompt.DISMISSED_REASON_ERROR);
+ }
+
+ @Test
+ public void testSendsReasonDismissedBySystemServer_whenDismissedByServer() throws Exception {
+ showDialog(BiometricPrompt.TYPE_FACE);
+ mBiometricDialogImpl.onDismissed(DialogViewCallback.DISMISSED_BY_SYSTEM_SERVER);
+ verify(mReceiver).onDialogDismissed(BiometricPrompt.DISMISSED_REASON_SERVER_REQUESTED);
+ }
+
+ // Statusbar tests
+
+ @Test
+ public void testShowInvoked_whenSystemRequested()
+ throws Exception {
+ showDialog(BiometricPrompt.TYPE_FACE);
+ verify(mDialog1).show(any(), eq(false) /* skipIntro */);
+ }
+
+ @Test
+ public void testOnAuthenticationSucceededInvoked_whenSystemRequested() throws Exception {
+ showDialog(BiometricPrompt.TYPE_FACE);
+ mBiometricDialogImpl.onBiometricAuthenticated(true, null /* failureReason */);
+ verify(mDialog1).onAuthenticationSucceeded();
+ }
+
+ @Test
+ public void testOnAuthenticationFailedInvoked_whenSystemRequested() throws Exception {
+ showDialog(BiometricPrompt.TYPE_FACE);
+ final String failureReason = "failure reason";
+ mBiometricDialogImpl.onBiometricAuthenticated(false, failureReason);
+
+ ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
+ verify(mDialog1).onAuthenticationFailed(captor.capture());
+
+ assertEquals(captor.getValue(), failureReason);
+ }
+
+ @Test
+ public void testOnHelpInvoked_whenSystemRequested() throws Exception {
+ showDialog(BiometricPrompt.TYPE_FACE);
+ final String helpMessage = "help";
+ mBiometricDialogImpl.onBiometricHelp(helpMessage);
+
+ ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
+ verify(mDialog1).onHelp(captor.capture());
+
+ assertEquals(captor.getValue(), helpMessage);
+ }
+
+ @Test
+ public void testOnErrorInvoked_whenSystemRequested() throws Exception {
+ showDialog(BiometricPrompt.TYPE_FACE);
+ final String errMessage = "error message";
+ mBiometricDialogImpl.onBiometricError(errMessage);
+
+ ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
+ verify(mDialog1).onError(captor.capture());
+
+ assertEquals(captor.getValue(), errMessage);
+ }
+
+ @Test
+ public void testDismissWithoutCallbackInvoked_whenSystemRequested() throws Exception {
+ showDialog(BiometricPrompt.TYPE_FACE);
+ mBiometricDialogImpl.hideBiometricDialog();
+ verify(mDialog1).dismissFromSystemServer();
+ }
+
+ @Test
+ public void testClientNotified_whenDismissedBySystemServer() throws Exception {
+ showDialog(BiometricPrompt.TYPE_FACE);
+ mBiometricDialogImpl.hideBiometricDialog();
+ verify(mDialog1).dismissFromSystemServer();
+
+ assertNotNull(mBiometricDialogImpl.mCurrentDialog);
+ assertNotNull(mBiometricDialogImpl.mReceiver);
+ }
+
+ // Corner case tests
+
+ @Test
+ public void testShowNewDialog_beforeOldDialogDismissed_SkipsAnimations() throws Exception {
+ showDialog(BiometricPrompt.TYPE_FACE);
+ verify(mDialog1).show(any(), eq(false) /* skipIntro */);
+
+ showDialog(BiometricPrompt.TYPE_FACE);
+
+ // First dialog should be dismissed without animation
+ verify(mDialog1).dismissWithoutCallback(eq(false) /* animate */);
+
+ // Second dialog should be shown without animation
+ verify(mDialog2).show(any(), eq(true)) /* skipIntro */;
+ }
+
+ @Test
+ public void testConfigurationPersists_whenOnConfigurationChanged() throws Exception {
+ showDialog(BiometricPrompt.TYPE_FACE);
+ verify(mDialog1).show(any(), eq(false) /* skipIntro */);
+
+ mBiometricDialogImpl.onConfigurationChanged(new Configuration());
+
+ ArgumentCaptor<Bundle> captor = ArgumentCaptor.forClass(Bundle.class);
+ verify(mDialog1).onSaveState(captor.capture());
+
+ // Old dialog doesn't animate
+ verify(mDialog1).dismissWithoutCallback(eq(false /* animate */));
+
+ // Saved state is restored into new dialog
+ ArgumentCaptor<Bundle> captor2 = ArgumentCaptor.forClass(Bundle.class);
+ verify(mDialog2).restoreState(captor2.capture());
+
+ // Dialog for new configuration skips intro
+ verify(mDialog2).show(any(), eq(true) /* skipIntro */);
+
+ // TODO: This should check all values we want to save/restore
+ assertEquals(captor.getValue(), captor2.getValue());
+ }
+
+ @Test
+ public void testClientNotified_whenTaskStackChangesDuringAuthentication() throws Exception {
+ showDialog(BiometricPrompt.TYPE_FACE);
+
+ List<ActivityManager.RunningTaskInfo> tasks = new ArrayList<>();
+ ActivityManager.RunningTaskInfo taskInfo = mock(ActivityManager.RunningTaskInfo.class);
+ taskInfo.topActivity = mock(ComponentName.class);
+ when(taskInfo.topActivity.getPackageName()).thenReturn("other_package");
+ tasks.add(taskInfo);
+ when(mBiometricDialogImpl.mActivityTaskManager.getTasks(anyInt())).thenReturn(tasks);
+
+ mBiometricDialogImpl.mTaskStackListener.onTaskStackChanged();
+ waitForIdleSync();
+
+ assertNull(mBiometricDialogImpl.mCurrentDialog);
+ assertNull(mBiometricDialogImpl.mReceiver);
+ verify(mDialog1).dismissWithoutCallback(true /* animate */);
+ verify(mReceiver).onDialogDismissed(eq(BiometricPrompt.DISMISSED_REASON_USER_CANCEL));
+ }
+
+ // Helpers
+
+ private void showDialog(int type) {
+ mBiometricDialogImpl.showBiometricDialog(createTestDialogBundle(),
+ mReceiver /* receiver */,
+ type,
+ true /* requireConfirmation */,
+ 0 /* userId */,
+ "testPackage");
+ }
+
+ private Bundle createTestDialogBundle() {
+ Bundle bundle = new Bundle();
+
+ bundle.putCharSequence(BiometricPrompt.KEY_TITLE, "Title");
+ bundle.putCharSequence(BiometricPrompt.KEY_SUBTITLE, "Subtitle");
+ bundle.putCharSequence(BiometricPrompt.KEY_DESCRIPTION, "Description");
+ bundle.putCharSequence(BiometricPrompt.KEY_NEGATIVE_TEXT, "Negative Button");
+
+ // RequireConfirmation is a hint to BiometricService. This can be forced to be required
+ // by user settings, and should be tested in BiometricService.
+ bundle.putBoolean(BiometricPrompt.KEY_REQUIRE_CONFIRMATION, true);
+
+ return bundle;
+ }
+
+ private final class TestableBiometricDialogImpl extends BiometricDialogImpl {
+ private int mBuildCount = 0;
+
+ public TestableBiometricDialogImpl(Injector injector) {
+ super(injector);
+ }
+
+ @Override
+ protected BiometricDialog buildDialog(Bundle biometricPromptBundle,
+ boolean requireConfirmation, int userId, int type, String opPackageName) {
+ BiometricDialog dialog;
+ if (mBuildCount == 0) {
+ dialog = mDialog1;
+ } else if (mBuildCount == 1) {
+ dialog = mDialog2;
+ } else {
+ dialog = null;
+ }
+ mBuildCount++;
+ return dialog;
+ }
+ }
+
+ private final class MockInjector extends BiometricDialogImpl.Injector {
+ @Override
+ IActivityTaskManager getActivityTaskManager() {
+ return mock(IActivityTaskManager.class);
+ }
+ }
+}
+
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/BiometricDialogViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/BiometricDialogViewTest.java
new file mode 100644
index 0000000..bbdd837
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/BiometricDialogViewTest.java
@@ -0,0 +1,204 @@
+/*
+ * 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.biometrics.ui;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotSame;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.Mockito.spy;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.hardware.biometrics.BiometricPrompt;
+import android.os.Bundle;
+import android.os.UserManager;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableContext;
+import android.testing.TestableLooper.RunWithLooper;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.accessibility.AccessibilityManager;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.biometrics.DialogViewCallback;
+import com.android.systemui.keyguard.WakefulnessLifecycle;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+@SmallTest
+public class BiometricDialogViewTest extends SysuiTestCase {
+
+ FaceDialogView mFaceDialogView;
+
+ private static final String TITLE = "Title";
+ private static final String SUBTITLE = "Subtitle";
+ private static final String DESCRIPTION = "Description";
+ private static final String NEGATIVE_BUTTON = "Negative Button";
+
+ private static final String TEST_HELP = "Help";
+
+ TestableContext mTestableContext;
+ @Mock
+ private DialogViewCallback mCallback;
+ @Mock
+ private UserManager mUserManager;
+ @Mock
+ private DevicePolicyManager mDpm;
+
+ private static class Injector extends BiometricDialogView.Injector {
+ @Override
+ public WakefulnessLifecycle getWakefulnessLifecycle() {
+ final WakefulnessLifecycle lifecycle = new WakefulnessLifecycle();
+ lifecycle.dispatchFinishedWakingUp();
+ return lifecycle;
+ }
+ }
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mTestableContext = spy(mContext);
+ mTestableContext.addMockSystemService(UserManager.class, mUserManager);
+ mTestableContext.addMockSystemService(DevicePolicyManager.class, mDpm);
+ }
+
+ @Test
+ public void testContentStates_confirmationRequired_authenticated() {
+ mFaceDialogView = buildFaceDialogView(mTestableContext, mCallback,
+ true /* requireConfirmation */);
+ mFaceDialogView.onAttachedToWindow();
+
+ // When starting authentication
+ assertEquals(View.VISIBLE, mFaceDialogView.mTitleText.getVisibility());
+ assertEquals(View.VISIBLE, mFaceDialogView.mSubtitleText.getVisibility());
+ assertEquals(View.VISIBLE, mFaceDialogView.mDescriptionText.getVisibility());
+ assertEquals(View.INVISIBLE, mFaceDialogView.mErrorText.getVisibility());
+ assertEquals(View.VISIBLE, mFaceDialogView.mPositiveButton.getVisibility());
+ assertEquals(View.VISIBLE, mFaceDialogView.mNegativeButton.getVisibility());
+ assertEquals(View.GONE, mFaceDialogView.mTryAgainButton.getVisibility());
+
+ // Contents are as expected
+ assertTrue(TITLE.contentEquals(mFaceDialogView.mTitleText.getText()));
+ assertTrue(SUBTITLE.contentEquals(mFaceDialogView.mSubtitleText.getText()));
+ assertTrue(DESCRIPTION.contentEquals(mFaceDialogView.mDescriptionText.getText()));
+ assertTrue(mFaceDialogView.mPositiveButton.getText().toString()
+ .contentEquals(mContext.getString(R.string.biometric_dialog_confirm)));
+ assertTrue(NEGATIVE_BUTTON.contentEquals(mFaceDialogView.mNegativeButton.getText()));
+ assertTrue(mFaceDialogView.mTryAgainButton.getText().toString()
+ .contentEquals(mContext.getString(R.string.biometric_dialog_try_again)));
+
+ // When help message is received
+ mFaceDialogView.onHelp(TEST_HELP);
+ assertEquals(mFaceDialogView.mErrorText.getVisibility(), View.VISIBLE);
+ assertTrue(TEST_HELP.contentEquals(mFaceDialogView.mErrorText.getText()));
+
+ // When authenticated, confirm button comes out
+ mFaceDialogView.onAuthenticationSucceeded();
+ assertEquals(View.VISIBLE, mFaceDialogView.mPositiveButton.getVisibility());
+ assertEquals(true, mFaceDialogView.mPositiveButton.isEnabled());
+ }
+
+ @Test
+ public void testContentStates_confirmationNotRequired_authenticated() {
+ mFaceDialogView = buildFaceDialogView(mTestableContext, mCallback,
+ false /* requireConfirmation */);
+ mFaceDialogView.onAttachedToWindow();
+ mFaceDialogView.updateSize(FaceDialogView.SIZE_SMALL);
+
+ assertEquals(View.INVISIBLE, mFaceDialogView.mTitleText.getVisibility());
+ assertNotSame(View.VISIBLE, mFaceDialogView.mSubtitleText.getVisibility());
+ assertNotSame(View.VISIBLE, mFaceDialogView.mDescriptionText.getVisibility());
+ assertEquals(View.INVISIBLE, mFaceDialogView.mErrorText.getVisibility());
+ assertEquals(View.GONE, mFaceDialogView.mPositiveButton.getVisibility());
+ assertEquals(View.GONE, mFaceDialogView.mTryAgainButton.getVisibility());
+ assertEquals(View.GONE, mFaceDialogView.mTryAgainButton.getVisibility());
+ }
+
+ @Test
+ public void testContentStates_confirmationNotRequired_help() {
+ mFaceDialogView = buildFaceDialogView(mTestableContext, mCallback,
+ false /* requireConfirmation */);
+ mFaceDialogView.onAttachedToWindow();
+
+ mFaceDialogView.onHelp(TEST_HELP);
+ assertEquals(mFaceDialogView.mErrorText.getVisibility(), View.VISIBLE);
+ assertTrue(TEST_HELP.contentEquals(mFaceDialogView.mErrorText.getText()));
+ }
+
+ @Test
+ public void testBack_sendsUserCanceled() {
+ // TODO: Need robolectric framework to wait for handler to complete
+ }
+
+ @Test
+ public void testScreenOff_sendsUserCanceled() {
+ // TODO: Need robolectric framework to wait for handler to complete
+ }
+
+ @Test
+ public void testRestoreState_contentStatesCorrect() {
+ mFaceDialogView = buildFaceDialogView(mTestableContext, mCallback,
+ false /* requireConfirmation */);
+ mFaceDialogView.onAttachedToWindow();
+ mFaceDialogView.onAuthenticationFailed(TEST_HELP);
+
+ final Bundle bundle = new Bundle();
+ mFaceDialogView.onSaveState(bundle);
+
+ mFaceDialogView = buildFaceDialogView(mTestableContext, mCallback,
+ false /* requireConfirmation */);
+ mFaceDialogView.restoreState(bundle);
+ mFaceDialogView.onAttachedToWindow();
+
+ assertEquals(View.VISIBLE, mFaceDialogView.mTryAgainButton.getVisibility());
+ }
+
+ private FaceDialogView buildFaceDialogView(Context context, DialogViewCallback callback,
+ boolean requireConfirmation) {
+ return (FaceDialogView) new BiometricDialogView.Builder(context)
+ .setCallback(callback)
+ .setBiometricPromptBundle(createTestDialogBundle())
+ .setRequireConfirmation(requireConfirmation)
+ .setUserId(0)
+ .setOpPackageName("test_package")
+ .build(BiometricDialogView.Builder.TYPE_FACE, new Injector());
+ }
+
+ private Bundle createTestDialogBundle() {
+ Bundle bundle = new Bundle();
+
+ bundle.putCharSequence(BiometricPrompt.KEY_TITLE, TITLE);
+ bundle.putCharSequence(BiometricPrompt.KEY_SUBTITLE, SUBTITLE);
+ bundle.putCharSequence(BiometricPrompt.KEY_DESCRIPTION, DESCRIPTION);
+ bundle.putCharSequence(BiometricPrompt.KEY_NEGATIVE_TEXT, NEGATIVE_BUTTON);
+
+ // RequireConfirmation is a hint to BiometricService. This can be forced to be required
+ // by user settings, and should be tested in BiometricService.
+ bundle.putBoolean(BiometricPrompt.KEY_REQUIRE_CONFIRMATION, true);
+
+ return bundle;
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt
new file mode 100644
index 0000000..2bff548
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt
@@ -0,0 +1,142 @@
+/*
+ * 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.broadcast
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.IntentFilter
+import android.os.Handler
+import android.os.Looper
+import android.os.UserHandle
+import android.test.suitebuilder.annotation.SmallTest
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import com.android.systemui.SysuiTestCase
+import junit.framework.Assert.assertSame
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+@SmallTest
+class BroadcastDispatcherTest : SysuiTestCase() {
+
+ companion object {
+ val user0 = UserHandle.of(0)
+ val user1 = UserHandle.of(1)
+
+ fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture()
+ }
+
+ @Mock
+ private lateinit var mockContext: Context
+ @Mock
+ private lateinit var mockUBRUser0: UserBroadcastDispatcher
+ @Mock
+ private lateinit var mockUBRUser1: UserBroadcastDispatcher
+ @Mock
+ private lateinit var broadcastReceiver: BroadcastReceiver
+ @Mock
+ private lateinit var broadcastReceiverOther: BroadcastReceiver
+ @Mock
+ private lateinit var intentFilter: IntentFilter
+ @Mock
+ private lateinit var intentFilterOther: IntentFilter
+ @Mock
+ private lateinit var mockHandler: Handler
+
+ @Captor
+ private lateinit var argumentCaptor: ArgumentCaptor<ReceiverData>
+
+ private lateinit var testableLooper: TestableLooper
+ private lateinit var broadcastDispatcher: BroadcastDispatcher
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ testableLooper = TestableLooper.get(this)
+
+ broadcastDispatcher = TestBroadcastDispatcher(
+ mockContext,
+ Handler(testableLooper.looper),
+ testableLooper.looper,
+ mapOf(0 to mockUBRUser0, 1 to mockUBRUser1))
+ }
+
+ @Test
+ fun testAddingReceiverToCorrectUBR() {
+ broadcastDispatcher.registerReceiver(broadcastReceiver, intentFilter, mockHandler, user0)
+ broadcastDispatcher.registerReceiver(
+ broadcastReceiverOther, intentFilterOther, mockHandler, user1)
+
+ testableLooper.processAllMessages()
+
+ verify(mockUBRUser0).registerReceiver(capture(argumentCaptor))
+
+ assertSame(broadcastReceiver, argumentCaptor.value.receiver)
+ assertSame(intentFilter, argumentCaptor.value.filter)
+
+ verify(mockUBRUser1).registerReceiver(capture(argumentCaptor))
+ assertSame(broadcastReceiverOther, argumentCaptor.value.receiver)
+ assertSame(intentFilterOther, argumentCaptor.value.filter)
+ }
+
+ @Test
+ fun testRemovingReceiversRemovesFromAllUBR() {
+ broadcastDispatcher.registerReceiver(broadcastReceiver, intentFilter, mockHandler, user0)
+ broadcastDispatcher.registerReceiver(broadcastReceiver, intentFilter, mockHandler, user1)
+
+ broadcastDispatcher.unregisterReceiver(broadcastReceiver)
+
+ testableLooper.processAllMessages()
+
+ verify(mockUBRUser0).unregisterReceiver(broadcastReceiver)
+ verify(mockUBRUser1).unregisterReceiver(broadcastReceiver)
+ }
+
+ @Test
+ fun testRemoveReceiverFromUser() {
+ broadcastDispatcher.registerReceiver(broadcastReceiver, intentFilter, mockHandler, user0)
+ broadcastDispatcher.registerReceiver(broadcastReceiver, intentFilter, mockHandler, user1)
+
+ broadcastDispatcher.unregisterReceiverForUser(broadcastReceiver, user0)
+
+ testableLooper.processAllMessages()
+
+ verify(mockUBRUser0).unregisterReceiver(broadcastReceiver)
+ verify(mockUBRUser1, never()).unregisterReceiver(broadcastReceiver)
+ }
+
+ private class TestBroadcastDispatcher(
+ context: Context,
+ mainHandler: Handler,
+ bgLooper: Looper,
+ var mockUBRMap: Map<Int, UserBroadcastDispatcher>
+ ) : BroadcastDispatcher(context, mainHandler, bgLooper) {
+ override fun createUBRForUser(userId: Int): UserBroadcastDispatcher {
+ return mockUBRMap.getOrDefault(userId, mock(UserBroadcastDispatcher::class.java))
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/broadcast/UserBroadcastDispatcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/broadcast/UserBroadcastDispatcherTest.kt
new file mode 100644
index 0000000..011c2cd
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/broadcast/UserBroadcastDispatcherTest.kt
@@ -0,0 +1,230 @@
+/*
+ * 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.broadcast
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.os.Handler
+import android.os.UserHandle
+import android.test.suitebuilder.annotation.SmallTest
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import com.android.systemui.SysuiTestCase
+import junit.framework.Assert.assertEquals
+import junit.framework.Assert.assertFalse
+import junit.framework.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.Mockito.anyString
+import org.mockito.Mockito.atLeastOnce
+import org.mockito.Mockito.never
+import org.mockito.Mockito.reset
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+@SmallTest
+class UserBroadcastDispatcherTest : SysuiTestCase() {
+
+ companion object {
+ private const val ACTION_1 = "com.android.systemui.tests.ACTION_1"
+ private const val ACTION_2 = "com.android.systemui.tests.ACTION_2"
+ private const val CATEGORY_1 = "com.android.systemui.tests.CATEGORY_1"
+ private const val CATEGORY_2 = "com.android.systemui.tests.CATEGORY_2"
+ private const val USER_ID = 0
+ private val USER_HANDLE = UserHandle.of(USER_ID)
+
+ fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture()
+ }
+
+ @Mock
+ private lateinit var broadcastReceiver: BroadcastReceiver
+ @Mock
+ private lateinit var broadcastReceiverOther: BroadcastReceiver
+ @Mock
+ private lateinit var mockContext: Context
+ @Mock
+ private lateinit var mockHandler: Handler
+
+ @Captor
+ private lateinit var argumentCaptor: ArgumentCaptor<IntentFilter>
+
+ private lateinit var testableLooper: TestableLooper
+ private lateinit var universalBroadcastReceiver: UserBroadcastDispatcher
+ private lateinit var intentFilter: IntentFilter
+ private lateinit var intentFilterOther: IntentFilter
+ private lateinit var handler: Handler
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ testableLooper = TestableLooper.get(this)
+ handler = Handler(testableLooper.looper)
+
+ universalBroadcastReceiver = UserBroadcastDispatcher(
+ mockContext, USER_ID, handler, testableLooper.looper)
+ }
+
+ @Test
+ fun testNotRegisteredOnStart() {
+ testableLooper.processAllMessages()
+ verify(mockContext, never()).registerReceiver(any(), any())
+ verify(mockContext, never()).registerReceiver(any(), any(), anyInt())
+ verify(mockContext, never()).registerReceiver(any(), any(), anyString(), any())
+ verify(mockContext, never()).registerReceiver(any(), any(), anyString(), any(), anyInt())
+ verify(mockContext, never()).registerReceiverAsUser(any(), any(), any(), anyString(), any())
+ }
+
+ @Test
+ fun testSingleReceiverRegistered() {
+ intentFilter = IntentFilter(ACTION_1)
+
+ universalBroadcastReceiver.registerReceiver(
+ ReceiverData(broadcastReceiver, intentFilter, mockHandler, USER_HANDLE))
+ testableLooper.processAllMessages()
+
+ assertTrue(universalBroadcastReceiver.isRegistered())
+ verify(mockContext).registerReceiverAsUser(
+ any(),
+ eq(USER_HANDLE),
+ capture(argumentCaptor),
+ any(),
+ any())
+ assertEquals(1, argumentCaptor.value.countActions())
+ assertTrue(argumentCaptor.value.hasAction(ACTION_1))
+ assertEquals(0, argumentCaptor.value.countCategories())
+ }
+
+ @Test
+ fun testSingleReceiverUnregistered() {
+ intentFilter = IntentFilter(ACTION_1)
+
+ universalBroadcastReceiver.registerReceiver(
+ ReceiverData(broadcastReceiver, intentFilter, mockHandler, USER_HANDLE))
+ testableLooper.processAllMessages()
+ reset(mockContext)
+
+ assertTrue(universalBroadcastReceiver.isRegistered())
+
+ universalBroadcastReceiver.unregisterReceiver(broadcastReceiver)
+ testableLooper.processAllMessages()
+
+ verify(mockContext, atLeastOnce()).unregisterReceiver(any())
+ verify(mockContext, never()).registerReceiverAsUser(any(), any(), any(), any(), any())
+ assertFalse(universalBroadcastReceiver.isRegistered())
+ }
+
+ @Test
+ fun testFilterHasAllActionsAndCategories_twoReceivers() {
+ intentFilter = IntentFilter(ACTION_1)
+ intentFilterOther = IntentFilter(ACTION_2).apply {
+ addCategory(CATEGORY_1)
+ addCategory(CATEGORY_2)
+ }
+
+ universalBroadcastReceiver.registerReceiver(
+ ReceiverData(broadcastReceiver, intentFilter, mockHandler, USER_HANDLE))
+ universalBroadcastReceiver.registerReceiver(
+ ReceiverData(broadcastReceiverOther, intentFilterOther, mockHandler, USER_HANDLE))
+
+ testableLooper.processAllMessages()
+ assertTrue(universalBroadcastReceiver.isRegistered())
+
+ verify(mockContext, times(2)).registerReceiverAsUser(
+ any(),
+ eq(USER_HANDLE),
+ capture(argumentCaptor),
+ any(),
+ any())
+
+ val lastFilter = argumentCaptor.value
+
+ assertTrue(lastFilter.hasAction(ACTION_1))
+ assertTrue(lastFilter.hasAction(ACTION_2))
+ assertTrue(lastFilter.hasCategory(CATEGORY_1))
+ assertTrue(lastFilter.hasCategory(CATEGORY_1))
+ }
+
+ @Test
+ fun testDispatchToCorrectReceiver() {
+ intentFilter = IntentFilter(ACTION_1)
+ intentFilterOther = IntentFilter(ACTION_2)
+
+ universalBroadcastReceiver.registerReceiver(
+ ReceiverData(broadcastReceiver, intentFilter, handler, USER_HANDLE))
+ universalBroadcastReceiver.registerReceiver(
+ ReceiverData(broadcastReceiverOther, intentFilterOther, handler, USER_HANDLE))
+
+ val intent = Intent(ACTION_2)
+
+ universalBroadcastReceiver.onReceive(mockContext, intent)
+ testableLooper.processAllMessages()
+
+ verify(broadcastReceiver, never()).onReceive(any(), any())
+ verify(broadcastReceiverOther).onReceive(mockContext, intent)
+ }
+
+ @Test
+ fun testDispatchToCorrectReceiver_differentFiltersSameReceiver() {
+ intentFilter = IntentFilter(ACTION_1)
+ intentFilterOther = IntentFilter(ACTION_2)
+
+ universalBroadcastReceiver.registerReceiver(
+ ReceiverData(broadcastReceiver, intentFilter, handler, USER_HANDLE))
+ universalBroadcastReceiver.registerReceiver(
+ ReceiverData(broadcastReceiver, intentFilterOther, handler, USER_HANDLE))
+
+ val intent = Intent(ACTION_2)
+
+ universalBroadcastReceiver.onReceive(mockContext, intent)
+ testableLooper.processAllMessages()
+
+ verify(broadcastReceiver).onReceive(mockContext, intent)
+ }
+
+ @Test
+ fun testDispatchIntentWithoutCategories() {
+ intentFilter = IntentFilter(ACTION_1)
+ intentFilter.addCategory(CATEGORY_1)
+ intentFilterOther = IntentFilter(ACTION_1)
+ intentFilterOther.addCategory(CATEGORY_2)
+
+ universalBroadcastReceiver.registerReceiver(
+ ReceiverData(broadcastReceiver, intentFilter, handler, USER_HANDLE))
+ universalBroadcastReceiver.registerReceiver(
+ ReceiverData(broadcastReceiverOther, intentFilterOther, handler, USER_HANDLE))
+
+ val intent = Intent(ACTION_1)
+
+ universalBroadcastReceiver.onReceive(mockContext, intent)
+ testableLooper.processAllMessages()
+
+ verify(broadcastReceiver).onReceive(mockContext, intent)
+ verify(broadcastReceiverOther).onReceive(mockContext, intent)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ZigZagClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ZigZagClassifierTest.java
index 25a1a75..fb4c1ec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ZigZagClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ZigZagClassifierTest.java
@@ -133,8 +133,8 @@
// This test looks just like testPass_horizontalZigZagVerticalStraight but with
// a shorter y range, making it look more crooked.
appendMoveEvent(0, 0);
- appendMoveEvent(5, 10);
- appendMoveEvent(-5, 20);
+ appendMoveEvent(6, 10);
+ appendMoveEvent(-6, 20);
assertThat(mClassifier.isFalseTouch(), is(true));
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
index 1e1f2156..b252a0d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -365,4 +365,45 @@
waitForIdleSync();
verify(mCallbacks).onRecentsAnimationStateChanged(eq(true));
}
+
+ @Test
+ public void testShowBiometricDialog() {
+ Bundle bundle = new Bundle();
+ String packageName = "test";
+ mCommandQueue.showBiometricDialog(bundle, null /* receiver */, 1, true, 3, packageName);
+ waitForIdleSync();
+ verify(mCallbacks).showBiometricDialog(eq(bundle), eq(null), eq(1), eq(true), eq(3),
+ eq(packageName));
+ }
+
+ @Test
+ public void testOnBiometricAuthenticated() {
+ String failureReason = "test_failure_reason";
+ mCommandQueue.onBiometricAuthenticated(true /* authenticated */, failureReason);
+ waitForIdleSync();
+ verify(mCallbacks).onBiometricAuthenticated(eq(true), eq(failureReason));
+ }
+
+ @Test
+ public void testOnBiometricHelp() {
+ String helpMessage = "test_help_message";
+ mCommandQueue.onBiometricHelp(helpMessage);
+ waitForIdleSync();
+ verify(mCallbacks).onBiometricHelp(eq(helpMessage));
+ }
+
+ @Test
+ public void testOnBiometricError() {
+ String errorMessage = "test_error_message";
+ mCommandQueue.onBiometricError(errorMessage);
+ waitForIdleSync();
+ verify(mCallbacks).onBiometricError(eq(errorMessage));
+ }
+
+ @Test
+ public void testHideBiometricDialog() {
+ mCommandQueue.hideBiometricDialog();
+ waitForIdleSync();
+ verify(mCallbacks).hideBiometricDialog();
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java
index 3e4c4d6..556ed5c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java
@@ -73,6 +73,7 @@
any(Handler.class));
mController = new HotspotControllerImpl(mContext, new Handler(mLooper.getLooper()));
+ mController.handleSetListening(true);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index 9ae9ceb..e691b7d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -228,6 +228,18 @@
NetworkControllerImpl.Config.add5GIconMapping("connected:5g", mConfig);
}
+ public void setupNr5GIconConfigurationForNotRestrictedRrcCon() {
+ NetworkControllerImpl.Config.add5GIconMapping("connected_mmwave:5g_plus", mConfig);
+ NetworkControllerImpl.Config.add5GIconMapping("connected:5g_plus", mConfig);
+ NetworkControllerImpl.Config.add5GIconMapping("not_restricted_rrc_con:5g", mConfig);
+ }
+
+ public void setupNr5GIconConfigurationForNotRestrictedRrcIdle() {
+ NetworkControllerImpl.Config.add5GIconMapping("connected_mmwave:5g_plus", mConfig);
+ NetworkControllerImpl.Config.add5GIconMapping("connected:5g_plus", mConfig);
+ NetworkControllerImpl.Config.add5GIconMapping("not_restricted_rrc_idle:5g", mConfig);
+ }
+
public void setConnectivityViaBroadcast(
int networkType, boolean validated, boolean isConnected) {
setConnectivityCommon(networkType, validated, isConnected);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
index 5128675..f0394da 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
@@ -175,6 +175,35 @@
}
@Test
+ public void testNr5GIcon_NrNotRestrictedRrcCon_show5GIcon() {
+ setupNr5GIconConfigurationForNotRestrictedRrcCon();
+ setupDefaultSignal();
+ updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
+ TelephonyManager.NETWORK_TYPE_LTE);
+ updateDataActivity(TelephonyManager.DATA_ACTIVITY_INOUT);
+ ServiceState ss = Mockito.mock(ServiceState.class);
+ doReturn(NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED).when(ss).getNrState();
+ mPhoneStateListener.onServiceStateChanged(ss);
+
+ verifyLastMobileDataIndicators(true, DEFAULT_SIGNAL_STRENGTH, TelephonyIcons.ICON_5G,
+ true, DEFAULT_QS_SIGNAL_STRENGTH, TelephonyIcons.ICON_5G, true, true);
+ }
+
+ @Test
+ public void testNr5GIcon_NrNotRestrictedRrcIdle_show5GIcon() {
+ setupNr5GIconConfigurationForNotRestrictedRrcIdle();
+ setupDefaultSignal();
+ updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
+ TelephonyManager.NETWORK_TYPE_LTE);
+ updateDataActivity(TelephonyManager.DATA_ACTIVITY_DORMANT);
+ ServiceState ss = Mockito.mock(ServiceState.class);
+ doReturn(NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED).when(ss).getNrState();
+ mPhoneStateListener.onServiceStateChanged(ss);
+
+ verifyDataIndicators(TelephonyIcons.ICON_5G);
+ }
+
+ @Test
public void testNr5GIcon_NrConnectedWithoutMMWave_show5GIcon() {
setupDefaultNr5GIconConfiguration();
setupDefaultSignal();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeHotspotController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeHotspotController.java
index 016160a..c9681ac 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeHotspotController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeHotspotController.java
@@ -26,6 +26,10 @@
}
@Override
+ public void handleSetListening(boolean listening) {
+ }
+
+ @Override
public boolean isHotspotEnabled() {
return false;
}
diff --git a/services/Android.bp b/services/Android.bp
index b08d1a8..54157d0 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -35,6 +35,7 @@
"services.usage",
"services.usb",
"services.voiceinteraction",
+ "services.wifi",
"android.hidl.base-V1.0-java",
],
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index 18b6f90..c733d3b 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -29,8 +29,8 @@
import android.view.MotionEvent;
import android.view.accessibility.AccessibilityEvent;
-import com.android.server.accessibility.gestures.TouchExplorer;
import com.android.server.LocalServices;
+import com.android.server.accessibility.gestures.TouchExplorer;
import com.android.server.policy.WindowManagerPolicy;
import java.util.ArrayList;
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index d058b9a..893e4e4 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -2531,10 +2531,9 @@
// to create event handler per display. The events should be handled by the
// display which is overlaid by it.
final Display display = displays[i];
- if (display.getType() == Display.TYPE_OVERLAY) {
- continue;
+ if (isValidDisplay(display)) {
+ mDisplaysList.add(display);
}
- mDisplaysList.add(display);
}
}
}
@@ -2542,7 +2541,7 @@
@Override
public void onDisplayAdded(int displayId) {
final Display display = mDisplayManager.getDisplay(displayId);
- if (display == null || display.getType() == Display.TYPE_OVERLAY) {
+ if (!isValidDisplay(display)) {
return;
}
@@ -2593,6 +2592,19 @@
public void onDisplayChanged(int displayId) {
/* do nothing */
}
+
+ private boolean isValidDisplay(@Nullable Display display) {
+ if (display == null || display.getType() == Display.TYPE_OVERLAY) {
+ return false;
+ }
+ // Private virtual displays are created by the ap and is not allowed to access by other
+ // aps. We assume we could ignore them.
+ if ((display.getType() == Display.TYPE_VIRTUAL
+ && (display.getFlags() & Display.FLAG_PRIVATE) != 0)) {
+ return false;
+ }
+ return true;
+ }
}
/** Represents an {@link AccessibilityManager} */
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
index 9687098..c9efe36 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
@@ -872,8 +872,8 @@
RemoteAccessibilityConnection wrapper = new RemoteAccessibilityConnection(
windowId, connection, packageName, resolvedUid, resolvedUserId);
wrapper.linkToDeath();
- getInteractionConnectionsForUserLocked(userId).put(windowId, wrapper);
- getWindowTokensForUserLocked(userId).put(windowId, windowToken.asBinder());
+ getInteractionConnectionsForUserLocked(resolvedUserId).put(windowId, wrapper);
+ getWindowTokensForUserLocked(resolvedUserId).put(windowId, windowToken.asBinder());
if (DEBUG) {
Slog.i(LOG_TAG, "Added user connection for pid:" + Binder.getCallingPid()
+ " with windowId: " + windowId
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 8032e1b..4579a3d 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -301,6 +301,11 @@
+ "mForAugmentedAutofillOnly: %s", mForAugmentedAutofillOnly);
return;
}
+ if (mCurrentViewId == null) {
+ Slog.w(TAG, "No current view id - session might have finished");
+ return;
+ }
+
final AssistStructure structure = resultData.getParcelable(ASSIST_KEY_STRUCTURE);
if (structure == null) {
Slog.e(TAG, "No assist structure - app might have crashed providing it");
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index dc0bdb3..222a6f2 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2014 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.
@@ -18,11 +18,15 @@
import static com.android.internal.util.Preconditions.checkNotNull;
+import static java.util.Collections.emptySet;
+
import android.Manifest;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
+import android.app.admin.DevicePolicyManager;
import android.app.backup.BackupManager;
+import android.app.backup.IBackupManager;
import android.app.backup.IBackupManagerMonitor;
import android.app.backup.IBackupObserver;
import android.app.backup.IFullBackupRestoreObserver;
@@ -31,24 +35,37 @@
import android.app.job.JobParameters;
import android.app.job.JobScheduler;
import android.app.job.JobService;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Binder;
+import android.os.FileUtils;
+import android.os.Handler;
+import android.os.HandlerThread;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Slog;
import android.util.SparseArray;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils;
+import com.android.server.SystemConfig;
import com.android.server.SystemService;
+import com.android.server.backup.utils.RandomAccessFileUtils;
+import java.io.File;
import java.io.FileDescriptor;
+import java.io.IOException;
import java.io.PrintWriter;
import java.util.Set;
@@ -58,8 +75,20 @@
* <p>This class is responsible for handling user-aware operations and acts as a delegator, routing
* incoming calls to the appropriate per-user {@link UserBackupManagerService} to handle the
* corresponding backup/restore operation.
+ *
+ * <p>It also determines whether the backup service is available. It can be disabled in the
+ * following two ways:
+ *
+ * <ul>
+ * <li>Temporary - call {@link #setBackupServiceActive(int, boolean)}, or
+ * <li>Permanent - set the system property {@link #BACKUP_DISABLE_PROPERTY} to true.
+ * </ul>
+ *
+ * Temporary disabling is controlled by {@link #setBackupServiceActive(int, boolean)} through
+ * privileged callers (currently {@link DevicePolicyManager}). If called on {@link
+ * UserHandle#USER_SYSTEM}, backup is disabled for all users.
*/
-public class BackupManagerService {
+public class BackupManagerService extends IBackupManager.Stub {
public static final String TAG = "BackupManagerService";
public static final boolean DEBUG = true;
public static final boolean MORE_DEBUG = false;
@@ -68,50 +97,249 @@
@VisibleForTesting
static final String DUMP_RUNNING_USERS_MESSAGE = "Backup Manager is running for users:";
+ /**
+ * Name of file that disables the backup service. If this file exists, then backup is disabled
+ * for all users.
+ */
+ private static final String BACKUP_SUPPRESS_FILENAME = "backup-suppress";
+
+ /**
+ * Name of file for non-system users that enables the backup service for the user. Backup is
+ * disabled by default in non-system users.
+ */
+ private static final String BACKUP_ACTIVATED_FILENAME = "backup-activated";
+
+ /**
+ * Name of file for non-system users that remembers whether backup was explicitly activated or
+ * deactivated with a call to setBackupServiceActive.
+ */
+ private static final String REMEMBER_ACTIVATED_FILENAME = "backup-remember-activated";
+
+ // Product-level suppression of backup/restore.
+ private static final String BACKUP_DISABLE_PROPERTY = "ro.backup.disable";
+
+ private static final String BACKUP_THREAD = "backup";
+
+ static BackupManagerService sInstance;
+
+ static BackupManagerService getInstance() {
+ return checkNotNull(sInstance);
+ }
+
private final Context mContext;
- private final Trampoline mTrampoline;
+ private final UserManager mUserManager;
- // Keeps track of all unlocked users registered with this service. Indexed by user id.
- private final SparseArray<UserBackupManagerService> mServiceUsers = new SparseArray<>();
+ private final boolean mGlobalDisable;
+ // Lock to write backup suppress files.
+ // TODD(b/121198006): remove this object and synchronized all methods on "this".
+ private final Object mStateLock = new Object();
- /** Instantiate a new instance of {@link BackupManagerService}. */
- public BackupManagerService(Context context, Trampoline trampoline) {
- mContext = checkNotNull(context);
- mTrampoline = checkNotNull(trampoline);
+ private final Handler mHandler;
+ private final Set<ComponentName> mTransportWhitelist;
+
+ /** Keeps track of all unlocked users registered with this service. Indexed by user id. */
+ private final SparseArray<UserBackupManagerService> mUserServices;
+
+ private final BroadcastReceiver mUserRemovedReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
+ int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+ if (userId > 0) { // for only non system users
+ mHandler.post(() -> onRemovedNonSystemUser(userId));
+ }
+ }
+ }
+ };
+
+ public BackupManagerService(Context context) {
+ this(context, new SparseArray<>());
+ }
+
+ @VisibleForTesting
+ BackupManagerService(Context context, SparseArray<UserBackupManagerService> userServices) {
+ mContext = context;
+ mGlobalDisable = isBackupDisabled();
+ HandlerThread handlerThread =
+ new HandlerThread(BACKUP_THREAD, Process.THREAD_PRIORITY_BACKGROUND);
+ handlerThread.start();
+ mHandler = new Handler(handlerThread.getLooper());
+ mUserManager = UserManager.get(context);
+ mUserServices = userServices;
+ Set<ComponentName> transportWhitelist =
+ SystemConfig.getInstance().getBackupTransportWhitelist();
+ mTransportWhitelist = (transportWhitelist == null) ? emptySet() : transportWhitelist;
+ mContext.registerReceiver(
+ mUserRemovedReceiver, new IntentFilter(Intent.ACTION_USER_REMOVED));
+ }
+
+ // TODO: Remove this when we implement DI by injecting in the construtor.
+ @VisibleForTesting
+ Handler getBackupHandler() {
+ return mHandler;
+ }
+
+ protected boolean isBackupDisabled() {
+ return SystemProperties.getBoolean(BACKUP_DISABLE_PROPERTY, false);
+ }
+
+ protected int binderGetCallingUserId() {
+ return Binder.getCallingUserHandle().getIdentifier();
+ }
+
+ protected int binderGetCallingUid() {
+ return Binder.getCallingUid();
+ }
+
+ /** Stored in the system user's directory. */
+ protected File getSuppressFileForSystemUser() {
+ return new File(UserBackupManagerFiles.getBaseStateDir(UserHandle.USER_SYSTEM),
+ BACKUP_SUPPRESS_FILENAME);
+ }
+
+ /** Stored in the system user's directory and the file is indexed by the user it refers to. */
+ protected File getRememberActivatedFileForNonSystemUser(int userId) {
+ return UserBackupManagerFiles.getStateFileInSystemDir(REMEMBER_ACTIVATED_FILENAME, userId);
+ }
+
+ /** Stored in the system user's directory and the file is indexed by the user it refers to. */
+ protected File getActivatedFileForNonSystemUser(int userId) {
+ return UserBackupManagerFiles.getStateFileInSystemDir(BACKUP_ACTIVATED_FILENAME, userId);
}
/**
- * If {@code userId} is different from the calling user id, then the caller must hold the
- * android.permission.INTERACT_ACROSS_USERS_FULL permission.
- *
- * @param userId User id on which the backup operation is being requested.
- * @param message A message to include in the exception if it is thrown.
+ * Remove backup state for non system {@code userId} when the user is removed from the device.
+ * For non system users, backup state is stored in both the user's own dir and the system dir.
+ * When the user is removed, the user's own dir gets removed by the OS. This method ensures that
+ * the part of the user backup state which is in the system dir also gets removed.
*/
- private void enforceCallingPermissionOnUserId(@UserIdInt int userId, String message) {
- if (Binder.getCallingUserHandle().getIdentifier() != userId) {
- mContext.enforceCallingOrSelfPermission(
- Manifest.permission.INTERACT_ACROSS_USERS_FULL, message);
+ private void onRemovedNonSystemUser(int userId) {
+ Slog.i(TAG, "Removing state for non system user " + userId);
+ File dir = UserBackupManagerFiles.getStateDirInSystemDir(userId);
+ if (!FileUtils.deleteContentsAndDir(dir)) {
+ Slog.w(TAG, "Failed to delete state dir for removed user: " + userId);
}
}
- // ---------------------------------------------
- // USER LIFECYCLE CALLBACKS
- // ---------------------------------------------
+ // TODO (b/124359804) move to util method in FileUtils
+ private void createFile(File file) throws IOException {
+ if (file.exists()) {
+ return;
+ }
+
+ file.getParentFile().mkdirs();
+ if (!file.createNewFile()) {
+ Slog.w(TAG, "Failed to create file " + file.getPath());
+ }
+ }
+
+ // TODO (b/124359804) move to util method in FileUtils
+ private void deleteFile(File file) {
+ if (!file.exists()) {
+ return;
+ }
+
+ if (!file.delete()) {
+ Slog.w(TAG, "Failed to delete file " + file.getPath());
+ }
+ }
+
+ /**
+ * Deactivates the backup service for user {@code userId}. If this is the system user, it
+ * creates a suppress file which disables backup for all users. If this is a non-system user, it
+ * only deactivates backup for that user by deleting its activate file.
+ */
+ @GuardedBy("mStateLock")
+ private void deactivateBackupForUserLocked(int userId) throws IOException {
+ if (userId == UserHandle.USER_SYSTEM) {
+ createFile(getSuppressFileForSystemUser());
+ } else {
+ deleteFile(getActivatedFileForNonSystemUser(userId));
+ }
+ }
+
+ /**
+ * Enables the backup service for user {@code userId}. If this is the system user, it deletes
+ * the suppress file. If this is a non-system user, it creates the user's activate file. Note,
+ * deleting the suppress file does not automatically enable backup for non-system users, they
+ * need their own activate file in order to participate in the service.
+ */
+ @GuardedBy("mStateLock")
+ private void activateBackupForUserLocked(int userId) throws IOException {
+ if (userId == UserHandle.USER_SYSTEM) {
+ deleteFile(getSuppressFileForSystemUser());
+ } else {
+ createFile(getActivatedFileForNonSystemUser(userId));
+ }
+ }
+
+ // This method should not perform any I/O (e.g. do not call isBackupActivatedForUser),
+ // it's used in multiple places where I/O waits would cause system lock-ups.
+ private boolean isUserReadyForBackup(int userId) {
+ return mUserServices.get(UserHandle.USER_SYSTEM) != null
+ && mUserServices.get(userId) != null;
+ }
+
+ /**
+ * Backup is activated for the system user if the suppress file does not exist. Backup is
+ * activated for non-system users if the suppress file does not exist AND the user's activated
+ * file exists.
+ */
+ private boolean isBackupActivatedForUser(int userId) {
+ if (getSuppressFileForSystemUser().exists()) {
+ return false;
+ }
+
+ return userId == UserHandle.USER_SYSTEM
+ || getActivatedFileForNonSystemUser(userId).exists();
+ }
+
+ protected Context getContext() {
+ return mContext;
+ }
+
+ protected UserManager getUserManager() {
+ return mUserManager;
+ }
+
+ protected void postToHandler(Runnable runnable) {
+ mHandler.post(runnable);
+ }
+
+ /**
+ * Called from {@link BackupManagerService.Lifecycle} when a user {@code userId} is unlocked.
+ * Starts the backup service for this user if backup is active for this user. Offloads work onto
+ * the handler thread {@link #mHandlerThread} to keep unlock time low since backup is not
+ * essential for device functioning.
+ */
+ void onUnlockUser(int userId) {
+ postToHandler(() -> startServiceForUser(userId));
+ }
/**
* Starts the backup service for user {@code userId} by creating a new instance of {@link
* UserBackupManagerService} and registering it with this service.
*/
@VisibleForTesting
- protected void startServiceForUser(int userId, Set<ComponentName> transportWhitelist) {
- if (mServiceUsers.get(userId) != null) {
+ void startServiceForUser(int userId) {
+ // We know that the user is unlocked here because it is called from setBackupServiceActive
+ // and unlockUser which have these guarantees. So we can check if the file exists.
+ if (mGlobalDisable) {
+ Slog.i(TAG, "Backup service not supported");
+ return;
+ }
+ if (!isBackupActivatedForUser(userId)) {
+ Slog.i(TAG, "Backup not activated for user " + userId);
+ return;
+ }
+ if (mUserServices.get(userId) != null) {
Slog.i(TAG, "userId " + userId + " already started, so not starting again");
return;
}
-
+ Slog.i(TAG, "Starting service for user: " + userId);
UserBackupManagerService userBackupManagerService =
UserBackupManagerService.createAndInitializeService(
- userId, mContext, mTrampoline, transportWhitelist);
+ userId, mContext, this, mTransportWhitelist);
startServiceForUser(userId, userBackupManagerService);
}
@@ -120,7 +348,7 @@
* UserBackupManagerService} with this service and setting enabled state.
*/
void startServiceForUser(int userId, UserBackupManagerService userBackupManagerService) {
- mServiceUsers.put(userId, userBackupManagerService);
+ mUserServices.put(userId, userBackupManagerService);
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup enable");
userBackupManagerService.initializeBackupEnableState();
@@ -130,7 +358,7 @@
/** Stops the backup service for user {@code userId} when the user is stopped. */
@VisibleForTesting
protected void stopServiceForUser(int userId) {
- UserBackupManagerService userBackupManagerService = mServiceUsers.removeReturnOld(userId);
+ UserBackupManagerService userBackupManagerService = mUserServices.removeReturnOld(userId);
if (userBackupManagerService != null) {
userBackupManagerService.tearDownService();
@@ -140,11 +368,6 @@
}
}
- boolean isAbleToServeUser(int userId) {
- return getUserServices().get(UserHandle.USER_SYSTEM) != null
- && getUserServices().get(userId) != null;
- }
-
/**
* Returns a list of users currently unlocked that have a {@link UserBackupManagerService}
* registered.
@@ -154,43 +377,146 @@
* TODO: Return a copy or only expose read-only information through other means.
*/
@VisibleForTesting
- public SparseArray<UserBackupManagerService> getUserServices() {
- return mServiceUsers;
+ SparseArray<UserBackupManagerService> getUserServices() {
+ return mUserServices;
}
/**
- * Returns the {@link UserBackupManagerService} instance for the specified user {@code userId}.
- * If the user is not registered with the service (either the user is locked or not eligible for
- * the backup service) then return {@code null}.
- *
- * @param userId The id of the user to retrieve its instance of {@link
- * UserBackupManagerService}.
- * @param caller A {@link String} identifying the caller for logging purposes.
- * @throws SecurityException if {@code userId} is different from the calling user id and the
- * caller does NOT have the android.permission.INTERACT_ACROSS_USERS_FULL permission.
+ * Called from {@link BackupManagerService.Lifecycle} when a user {@code userId} is stopped.
+ * Offloads work onto the handler thread {@link #mHandlerThread} to keep stopping time low.
*/
- @Nullable
- @VisibleForTesting
- UserBackupManagerService getServiceForUserIfCallerHasPermission(
- @UserIdInt int userId, String caller) {
- enforceCallingPermissionOnUserId(userId, caller);
- UserBackupManagerService userBackupManagerService = mServiceUsers.get(userId);
- if (userBackupManagerService == null) {
- Slog.w(TAG, "Called " + caller + " for unknown user: " + userId);
- }
- return userBackupManagerService;
+ void onStopUser(int userId) {
+ postToHandler(
+ () -> {
+ if (!mGlobalDisable) {
+ Slog.i(TAG, "Stopping service for user: " + userId);
+ stopServiceForUser(userId);
+ }
+ });
}
- /*
- * The following methods are implementations of IBackupManager methods called from Trampoline.
- * They delegate to the appropriate per-user instance of UserBackupManagerService to perform the
- * action on the passed in user. Currently this is a straight redirection (see TODO).
- */
- // TODO (b/118520567): Stop hardcoding system user when we pass in user id as a parameter
+ /** Returns {@link UserBackupManagerService} for user {@code userId}. */
+ @Nullable
+ public UserBackupManagerService getUserService(int userId) {
+ return mUserServices.get(userId);
+ }
- // ---------------------------------------------
- // BACKUP AGENT OPERATIONS
- // ---------------------------------------------
+ /**
+ * The system user and managed profiles can only be acted on by callers in the system or root
+ * processes. Other users can be acted on by callers who have both android.permission.BACKUP and
+ * android.permission.INTERACT_ACROSS_USERS_FULL permissions.
+ */
+ private void enforcePermissionsOnUser(int userId) throws SecurityException {
+ boolean isRestrictedUser =
+ userId == UserHandle.USER_SYSTEM
+ || getUserManager().getUserInfo(userId).isManagedProfile();
+
+ if (isRestrictedUser) {
+ int caller = binderGetCallingUid();
+ if (caller != Process.SYSTEM_UID && caller != Process.ROOT_UID) {
+ throw new SecurityException("No permission to configure backup activity");
+ }
+ } else {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.BACKUP, "No permission to configure backup activity");
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+ "No permission to configure backup activity");
+ }
+ }
+
+ /**
+ * Only privileged callers should be changing the backup state. Deactivating backup in the
+ * system user also deactivates backup in all users. We are not guaranteed that {@code userId}
+ * is unlocked at this point yet, so handle both cases.
+ */
+ public void setBackupServiceActive(int userId, boolean makeActive) {
+ enforcePermissionsOnUser(userId);
+
+ // In Q, backup is OFF by default for non-system users. In the future, we will change that
+ // to ON unless backup was explicitly deactivated with a (permissioned) call to
+ // setBackupServiceActive.
+ // Therefore, remember this for use in the future. Basically the default in the future will
+ // be: rememberFile.exists() ? rememberFile.value() : ON
+ // Note that this has to be done right after the permission checks and before any other
+ // action since we need to remember that a permissioned call was made irrespective of
+ // whether the call changes the state or not.
+ if (userId != UserHandle.USER_SYSTEM) {
+ try {
+ File rememberFile = getRememberActivatedFileForNonSystemUser(userId);
+ createFile(rememberFile);
+ RandomAccessFileUtils.writeBoolean(rememberFile, makeActive);
+ } catch (IOException e) {
+ Slog.e(TAG, "Unable to persist backup service activity", e);
+ }
+ }
+
+ if (mGlobalDisable) {
+ Slog.i(TAG, "Backup service not supported");
+ return;
+ }
+
+ synchronized (mStateLock) {
+ Slog.i(TAG, "Making backup " + (makeActive ? "" : "in") + "active");
+ if (makeActive) {
+ try {
+ activateBackupForUserLocked(userId);
+ } catch (IOException e) {
+ Slog.e(TAG, "Unable to persist backup service activity");
+ }
+
+ // If the user is unlocked, we can start the backup service for it. Otherwise we
+ // will start the service when the user is unlocked as part of its unlock callback.
+ if (getUserManager().isUserUnlocked(userId)) {
+ // Clear calling identity as initialization enforces the system identity but we
+ // can be coming from shell.
+ long oldId = Binder.clearCallingIdentity();
+ try {
+ startServiceForUser(userId);
+ } finally {
+ Binder.restoreCallingIdentity(oldId);
+ }
+ }
+ } else {
+ try {
+ //TODO(b/121198006): what if this throws an exception?
+ deactivateBackupForUserLocked(userId);
+ } catch (IOException e) {
+ Slog.e(TAG, "Unable to persist backup service inactivity");
+ }
+ //TODO(b/121198006): loop through active users that have work profile and
+ // stop them as well.
+ onStopUser(userId);
+ }
+ }
+ }
+
+ // IBackupManager binder API
+
+ /**
+ * Querying activity state of backup service.
+ *
+ * @param userId The user in which the activity state of backup service is queried.
+ * @return true if the service is active.
+ */
+ @Override
+ public boolean isBackupServiceActive(int userId) {
+ synchronized (mStateLock) {
+ return !mGlobalDisable && isBackupActivatedForUser(userId);
+ }
+ }
+
+ @Override
+ public void dataChangedForUser(int userId, String packageName) throws RemoteException {
+ if (isUserReadyForBackup(userId)) {
+ dataChanged(userId, packageName);
+ }
+ }
+
+ @Override
+ public void dataChanged(String packageName) throws RemoteException {
+ dataChangedForUser(binderGetCallingUserId(), packageName);
+ }
/**
* An app's backup agent calls this method to let the service know that there's new data to
@@ -206,49 +532,18 @@
}
}
- /**
- * Callback: a requested backup agent has been instantiated. This should only be called from the
- * {@link ActivityManager}.
- */
- public void agentConnected(@UserIdInt int userId, String packageName, IBinder agentBinder) {
- UserBackupManagerService userBackupManagerService =
- getServiceForUserIfCallerHasPermission(userId, "agentConnected()");
-
- if (userBackupManagerService != null) {
- userBackupManagerService.agentConnected(packageName, agentBinder);
- }
- }
-
- /**
- * Callback: a backup agent has failed to come up, or has unexpectedly quit. This should only be
- * called from the {@link ActivityManager}.
- */
- public void agentDisconnected(@UserIdInt int userId, String packageName) {
- UserBackupManagerService userBackupManagerService =
- getServiceForUserIfCallerHasPermission(userId, "agentDisconnected()");
-
- if (userBackupManagerService != null) {
- userBackupManagerService.agentDisconnected(packageName);
- }
- }
-
- /**
- * Used by a currently-active backup agent to notify the service that it has completed its given
- * outstanding asynchronous backup/restore operation.
- */
- public void opComplete(@UserIdInt int userId, int token, long result) {
- UserBackupManagerService userBackupManagerService =
- getServiceForUserIfCallerHasPermission(userId, "opComplete()");
-
- if (userBackupManagerService != null) {
- userBackupManagerService.opComplete(token, result);
- }
- }
-
// ---------------------------------------------
// TRANSPORT OPERATIONS
// ---------------------------------------------
+ @Override
+ public void initializeTransportsForUser(
+ int userId, String[] transportNames, IBackupObserver observer) throws RemoteException {
+ if (isUserReadyForBackup(userId)) {
+ initializeTransports(userId, transportNames, observer);
+ }
+ }
+
/** Run an initialize operation for the given transports {@code transportNames}. */
public void initializeTransports(
@UserIdInt int userId, String[] transportNames, IBackupObserver observer) {
@@ -260,6 +555,14 @@
}
}
+ @Override
+ public void clearBackupDataForUser(int userId, String transportName, String packageName)
+ throws RemoteException {
+ if (isUserReadyForBackup(userId)) {
+ clearBackupData(userId, transportName, packageName);
+ }
+ }
+
/**
* Clear the given package {@code packageName}'s backup data from the transport {@code
* transportName}.
@@ -273,6 +576,340 @@
}
}
+ @Override
+ public void clearBackupData(String transportName, String packageName)
+ throws RemoteException {
+ clearBackupDataForUser(binderGetCallingUserId(), transportName, packageName);
+ }
+
+ @Override
+ public void agentConnectedForUser(int userId, String packageName, IBinder agent)
+ throws RemoteException {
+ if (isUserReadyForBackup(userId)) {
+ agentConnected(userId, packageName, agent);
+ }
+ }
+
+ @Override
+ public void agentConnected(String packageName, IBinder agent) throws RemoteException {
+ agentConnectedForUser(binderGetCallingUserId(), packageName, agent);
+ }
+
+ /**
+ * Callback: a requested backup agent has been instantiated. This should only be called from the
+ * {@link ActivityManager}.
+ */
+ public void agentConnected(@UserIdInt int userId, String packageName, IBinder agentBinder) {
+ UserBackupManagerService userBackupManagerService =
+ getServiceForUserIfCallerHasPermission(userId, "agentConnected()");
+
+ if (userBackupManagerService != null) {
+ userBackupManagerService.agentConnected(packageName, agentBinder);
+ }
+ }
+
+ @Override
+ public void agentDisconnectedForUser(int userId, String packageName) throws RemoteException {
+ if (isUserReadyForBackup(userId)) {
+ agentDisconnected(userId, packageName);
+ }
+ }
+
+ @Override
+ public void agentDisconnected(String packageName) throws RemoteException {
+ agentDisconnectedForUser(binderGetCallingUserId(), packageName);
+ }
+
+ /**
+ * Callback: a backup agent has failed to come up, or has unexpectedly quit. This should only be
+ * called from the {@link ActivityManager}.
+ */
+ public void agentDisconnected(@UserIdInt int userId, String packageName) {
+ UserBackupManagerService userBackupManagerService =
+ getServiceForUserIfCallerHasPermission(userId, "agentDisconnected()");
+
+ if (userBackupManagerService != null) {
+ userBackupManagerService.agentDisconnected(packageName);
+ }
+ }
+
+ @Override
+ public void restoreAtInstallForUser(int userId, String packageName, int token)
+ throws RemoteException {
+ if (isUserReadyForBackup(userId)) {
+ restoreAtInstall(userId, packageName, token);
+ }
+ }
+
+ @Override
+ public void restoreAtInstall(String packageName, int token) throws RemoteException {
+ restoreAtInstallForUser(binderGetCallingUserId(), packageName, token);
+ }
+
+ /**
+ * Used to run a restore pass for an application that is being installed. This should only be
+ * called from the {@link PackageManager}.
+ */
+ public void restoreAtInstall(@UserIdInt int userId, String packageName, int token) {
+ UserBackupManagerService userBackupManagerService =
+ getServiceForUserIfCallerHasPermission(userId, "restoreAtInstall()");
+
+ if (userBackupManagerService != null) {
+ userBackupManagerService.restoreAtInstall(packageName, token);
+ }
+ }
+
+ @Override
+ public void setBackupEnabledForUser(@UserIdInt int userId, boolean isEnabled)
+ throws RemoteException {
+ if (isUserReadyForBackup(userId)) {
+ setBackupEnabled(userId, isEnabled);
+ }
+ }
+
+ @Override
+ public void setBackupEnabled(boolean isEnabled) throws RemoteException {
+ setBackupEnabledForUser(binderGetCallingUserId(), isEnabled);
+ }
+
+ /** Enable/disable the backup service. This is user-configurable via backup settings. */
+ public void setBackupEnabled(@UserIdInt int userId, boolean enable) {
+ UserBackupManagerService userBackupManagerService =
+ getServiceForUserIfCallerHasPermission(userId, "setBackupEnabled()");
+
+ if (userBackupManagerService != null) {
+ userBackupManagerService.setBackupEnabled(enable);
+ }
+ }
+
+ @Override
+ public void setAutoRestoreForUser(int userId, boolean doAutoRestore) throws RemoteException {
+ if (isUserReadyForBackup(userId)) {
+ setAutoRestore(userId, doAutoRestore);
+ }
+ }
+
+ @Override
+ public void setAutoRestore(boolean doAutoRestore) throws RemoteException {
+ setAutoRestoreForUser(binderGetCallingUserId(), doAutoRestore);
+ }
+
+ /** Enable/disable automatic restore of app data at install time. */
+ public void setAutoRestore(@UserIdInt int userId, boolean autoRestore) {
+ UserBackupManagerService userBackupManagerService =
+ getServiceForUserIfCallerHasPermission(userId, "setAutoRestore()");
+
+ if (userBackupManagerService != null) {
+ userBackupManagerService.setAutoRestore(autoRestore);
+ }
+ }
+
+ @Override
+ public boolean isBackupEnabledForUser(@UserIdInt int userId) throws RemoteException {
+ return isUserReadyForBackup(userId) && isBackupEnabled(userId);
+ }
+
+ @Override
+ public boolean isBackupEnabled() throws RemoteException {
+ return isBackupEnabledForUser(binderGetCallingUserId());
+ }
+
+ /**
+ * Return {@code true} if the backup mechanism is currently enabled, else returns {@code false}.
+ */
+ public boolean isBackupEnabled(@UserIdInt int userId) {
+ UserBackupManagerService userBackupManagerService =
+ getServiceForUserIfCallerHasPermission(userId, "isBackupEnabled()");
+
+ return userBackupManagerService != null && userBackupManagerService.isBackupEnabled();
+ }
+
+ /** Sets the backup password used when running adb backup. */
+ @Override
+ public boolean setBackupPassword(String currentPassword, String newPassword) {
+ int userId = binderGetCallingUserId();
+ if (!isUserReadyForBackup(userId)) {
+ return false;
+ }
+ UserBackupManagerService userBackupManagerService =
+ getServiceForUserIfCallerHasPermission(
+ UserHandle.USER_SYSTEM, "setBackupPassword()");
+
+ return userBackupManagerService != null
+ && userBackupManagerService.setBackupPassword(currentPassword, newPassword);
+ }
+
+ /** Returns {@code true} if adb backup was run with a password, else returns {@code false}. */
+ @Override
+ public boolean hasBackupPassword() throws RemoteException {
+ int userId = binderGetCallingUserId();
+ if (!isUserReadyForBackup(userId)) {
+ return false;
+ }
+ UserBackupManagerService userBackupManagerService =
+ getServiceForUserIfCallerHasPermission(
+ UserHandle.USER_SYSTEM, "hasBackupPassword()");
+
+ return userBackupManagerService != null && userBackupManagerService.hasBackupPassword();
+ }
+
+ @Override
+ public void backupNowForUser(@UserIdInt int userId) throws RemoteException {
+ if (isUserReadyForBackup(userId)) {
+ backupNow(userId);
+ }
+ }
+
+ @Override
+ public void backupNow() throws RemoteException {
+ backupNowForUser(binderGetCallingUserId());
+ }
+
+ /**
+ * Run a backup pass immediately for any key-value backup applications that have declared that
+ * they have pending updates.
+ */
+ public void backupNow(@UserIdInt int userId) {
+ UserBackupManagerService userBackupManagerService =
+ getServiceForUserIfCallerHasPermission(userId, "backupNow()");
+
+ if (userBackupManagerService != null) {
+ userBackupManagerService.backupNow();
+ }
+ }
+
+ /**
+ * Used by 'adb backup' to run a backup pass for packages {@code packageNames} supplied via the
+ * command line, writing the resulting data stream to the supplied {@code fd}. This method is
+ * synchronous and does not return to the caller until the backup has been completed. It
+ * requires on-screen confirmation by the user.
+ */
+ @Override
+ public void adbBackup(
+ @UserIdInt int userId,
+ ParcelFileDescriptor fd,
+ boolean includeApks,
+ boolean includeObbs,
+ boolean includeShared,
+ boolean doWidgets,
+ boolean doAllApps,
+ boolean includeSystem,
+ boolean doCompress,
+ boolean doKeyValue,
+ String[] packageNames) {
+ if (!isUserReadyForBackup(userId)) {
+ return;
+ }
+ UserBackupManagerService userBackupManagerService =
+ getServiceForUserIfCallerHasPermission(userId, "adbBackup()");
+
+ if (userBackupManagerService != null) {
+ userBackupManagerService.adbBackup(
+ fd,
+ includeApks,
+ includeObbs,
+ includeShared,
+ doWidgets,
+ doAllApps,
+ includeSystem,
+ doCompress,
+ doKeyValue,
+ packageNames);
+ }
+ }
+
+ @Override
+ public void fullTransportBackupForUser(int userId, String[] packageNames)
+ throws RemoteException {
+ if (isUserReadyForBackup(userId)) {
+ fullTransportBackup(userId, packageNames);
+ }
+ }
+
+ /**
+ * Run a full backup pass for the given packages {@code packageNames}. Used by 'adb shell bmgr'.
+ */
+ public void fullTransportBackup(@UserIdInt int userId, String[] packageNames) {
+ UserBackupManagerService userBackupManagerService =
+ getServiceForUserIfCallerHasPermission(userId, "fullTransportBackup()");
+
+ if (userBackupManagerService != null) {
+ userBackupManagerService.fullTransportBackup(packageNames);
+ }
+ }
+
+ /**
+ * Used by 'adb restore' to run a restore pass reading from the supplied {@code fd}. This method
+ * is synchronous and does not return to the caller until the restore has been completed. It
+ * requires on-screen confirmation by the user.
+ */
+ @Override
+ public void adbRestore(@UserIdInt int userId, ParcelFileDescriptor fd) {
+ if (!isUserReadyForBackup(userId)) {
+ return;
+ }
+ UserBackupManagerService userBackupManagerService =
+ getServiceForUserIfCallerHasPermission(userId, "adbRestore()");
+
+ if (userBackupManagerService != null) {
+ userBackupManagerService.adbRestore(fd);
+ }
+ }
+
+ @Override
+ public void acknowledgeFullBackupOrRestoreForUser(
+ int userId,
+ int token,
+ boolean allow,
+ String curPassword,
+ String encryptionPassword,
+ IFullBackupRestoreObserver observer)
+ throws RemoteException {
+ if (isUserReadyForBackup(userId)) {
+ acknowledgeAdbBackupOrRestore(userId, token, allow,
+ curPassword, encryptionPassword, observer);
+ }
+ }
+
+ /**
+ * Confirm that the previously requested adb backup/restore operation can proceed. This is used
+ * to require a user-facing disclosure about the operation.
+ */
+ public void acknowledgeAdbBackupOrRestore(
+ @UserIdInt int userId,
+ int token,
+ boolean allow,
+ String currentPassword,
+ String encryptionPassword,
+ IFullBackupRestoreObserver observer) {
+ UserBackupManagerService userBackupManagerService =
+ getServiceForUserIfCallerHasPermission(userId, "acknowledgeAdbBackupOrRestore()");
+
+ if (userBackupManagerService != null) {
+ userBackupManagerService.acknowledgeAdbBackupOrRestore(
+ token, allow, currentPassword, encryptionPassword, observer);
+ }
+ }
+
+ @Override
+ public void acknowledgeFullBackupOrRestore(int token, boolean allow, String curPassword,
+ String encryptionPassword, IFullBackupRestoreObserver observer)
+ throws RemoteException {
+ acknowledgeFullBackupOrRestoreForUser(
+ binderGetCallingUserId(), token, allow, curPassword, encryptionPassword, observer);
+ }
+
+
+ @Override
+ public String getCurrentTransportForUser(int userId) throws RemoteException {
+ return (isUserReadyForBackup(userId)) ? getCurrentTransport(userId) : null;
+ }
+
+ @Override
+ public String getCurrentTransport() throws RemoteException {
+ return getCurrentTransportForUser(binderGetCallingUserId());
+ }
+
/** Return the name of the currently active transport. */
@Nullable
public String getCurrentTransport(@UserIdInt int userId) {
@@ -285,6 +922,16 @@
}
/**
+ * Returns the {@link ComponentName} of the host service of the selected transport or
+ * {@code null} if no transport selected or if the transport selected is not registered.
+ */
+ @Override
+ @Nullable
+ public ComponentName getCurrentTransportComponentForUser(int userId) {
+ return (isUserReadyForBackup(userId)) ? getCurrentTransportComponent(userId) : null;
+ }
+
+ /**
* Returns the {@link ComponentName} of the host service of the selected transport or {@code
* null} if no transport selected or if the transport selected is not registered.
*/
@@ -298,6 +945,11 @@
: userBackupManagerService.getCurrentTransportComponent();
}
+ @Override
+ public String[] listAllTransportsForUser(int userId) throws RemoteException {
+ return (isUserReadyForBackup(userId)) ? listAllTransports(userId) : null;
+ }
+
/** Report all known, available backup transports by name. */
@Nullable
public String[] listAllTransports(@UserIdInt int userId) {
@@ -309,6 +961,17 @@
: userBackupManagerService.listAllTransports();
}
+ @Override
+ public String[] listAllTransports() throws RemoteException {
+ return listAllTransportsForUser(binderGetCallingUserId());
+ }
+
+ @Override
+ public ComponentName[] listAllTransportComponentsForUser(int userId) throws RemoteException {
+ return (isUserReadyForBackup(userId))
+ ? listAllTransportComponents(userId) : null;
+ }
+
/** Report all known, available backup transports by {@link ComponentName}. */
@Nullable
public ComponentName[] listAllTransportComponents(@UserIdInt int userId) {
@@ -320,6 +983,43 @@
: userBackupManagerService.listAllTransportComponents();
}
+ @Override
+ public String[] getTransportWhitelist() {
+ int userId = binderGetCallingUserId();
+ if (!isUserReadyForBackup(userId)) {
+ return null;
+ }
+ // No permission check, intentionally.
+ String[] whitelistedTransports = new String[mTransportWhitelist.size()];
+ int i = 0;
+ for (ComponentName component : mTransportWhitelist) {
+ whitelistedTransports[i] = component.flattenToShortString();
+ i++;
+ }
+ return whitelistedTransports;
+ }
+
+ @Override
+ public void updateTransportAttributesForUser(
+ int userId,
+ ComponentName transportComponent,
+ String name,
+ @Nullable Intent configurationIntent,
+ String currentDestinationString,
+ @Nullable Intent dataManagementIntent,
+ CharSequence dataManagementLabel) {
+ if (isUserReadyForBackup(userId)) {
+ updateTransportAttributes(
+ userId,
+ transportComponent,
+ name,
+ configurationIntent,
+ currentDestinationString,
+ dataManagementIntent,
+ dataManagementLabel);
+ }
+ }
+
/**
* Update the attributes of the transport identified by {@code transportComponent}. If the
* specified transport has not been bound at least once (for registration), this call will be
@@ -365,6 +1065,18 @@
}
}
+ @Override
+ public String selectBackupTransportForUser(int userId, String transport)
+ throws RemoteException {
+ return (isUserReadyForBackup(userId))
+ ? selectBackupTransport(userId, transport) : null;
+ }
+
+ @Override
+ public String selectBackupTransport(String transport) throws RemoteException {
+ return selectBackupTransportForUser(binderGetCallingUserId(), transport);
+ }
+
/**
* Selects transport {@code transportName} and returns the previously selected transport.
*
@@ -382,6 +1094,22 @@
: userBackupManagerService.selectBackupTransport(transportName);
}
+ @Override
+ public void selectBackupTransportAsyncForUser(int userId, ComponentName transport,
+ ISelectBackupTransportCallback listener) throws RemoteException {
+ if (isUserReadyForBackup(userId)) {
+ selectBackupTransportAsync(userId, transport, listener);
+ } else {
+ if (listener != null) {
+ try {
+ listener.onFailure(BackupManager.ERROR_BACKUP_NOT_ALLOWED);
+ } catch (RemoteException ex) {
+ // ignore
+ }
+ }
+ }
+ }
+
/**
* Selects transport {@code transportComponent} asynchronously and notifies {@code listener}
* with the result upon completion.
@@ -398,6 +1126,19 @@
}
}
+ @Override
+ public Intent getConfigurationIntentForUser(int userId, String transport)
+ throws RemoteException {
+ return isUserReadyForBackup(userId) ? getConfigurationIntent(userId, transport)
+ : null;
+ }
+
+ @Override
+ public Intent getConfigurationIntent(String transport)
+ throws RemoteException {
+ return getConfigurationIntentForUser(binderGetCallingUserId(), transport);
+ }
+
/**
* Supply the configuration intent for the given transport. If the name is not one of the
* available transports, or if the transport does not supply any configuration UI, the method
@@ -409,59 +1150,19 @@
getServiceForUserIfCallerHasPermission(userId, "getConfigurationIntent()");
return userBackupManagerService == null
- ? null
- : userBackupManagerService.getConfigurationIntent(transportName);
+ ? null
+ : userBackupManagerService.getConfigurationIntent(transportName);
}
- /**
- * Sets the ancestral work profile for the calling user.
- *
- * <p> The ancestral work profile corresponds to the profile that was used to restore to the
- * callers profile.
- */
- public void setAncestralSerialNumber(long ancestralSerialNumber) {
- UserBackupManagerService userBackupManagerService =
- getServiceForUserIfCallerHasPermission(
- Binder.getCallingUserHandle().getIdentifier(),
- "setAncestralSerialNumber()");
-
- if (userBackupManagerService != null) {
- userBackupManagerService.setAncestralSerialNumber(ancestralSerialNumber);
- }
+ @Override
+ public String getDestinationStringForUser(int userId, String transport) throws RemoteException {
+ return isUserReadyForBackup(userId) ? getDestinationString(userId, transport)
+ : null;
}
- /**
- * Returns a {@link UserHandle} for the user that has {@code ancestralSerialNumber} as the
- * serial number of the its ancestral work profile or null if there is no {@link
- * UserBackupManagerService} associated with that user.
- *
- * <p> The ancestral work profile is set by {@link #setAncestralSerialNumber(long)}
- * and it corresponds to the profile that was used to restore to the callers profile.
- */
- @Nullable
- public UserHandle getUserForAncestralSerialNumber(long ancestralSerialNumber) {
- int callingUserId = Binder.getCallingUserHandle().getIdentifier();
- long oldId = Binder.clearCallingIdentity();
- final int[] userIds;
- try {
- userIds =
- mContext
- .getSystemService(UserManager.class)
- .getProfileIds(callingUserId, false);
- } finally {
- Binder.restoreCallingIdentity(oldId);
- }
-
- for (int userId : userIds) {
- UserBackupManagerService userBackupManagerService = getUserServices().get(userId);
- if (userBackupManagerService != null) {
- if (userBackupManagerService.getAncestralSerialNumber() == ancestralSerialNumber) {
- return UserHandle.of(userId);
- }
- }
- }
-
- return null;
+ @Override
+ public String getDestinationString(String transport) throws RemoteException {
+ return getDestinationStringForUser(binderGetCallingUserId(), transport);
}
/**
@@ -483,6 +1184,19 @@
: userBackupManagerService.getDestinationString(transportName);
}
+ @Override
+ public Intent getDataManagementIntentForUser(int userId, String transport)
+ throws RemoteException {
+ return isUserReadyForBackup(userId)
+ ? getDataManagementIntent(userId, transport) : null;
+ }
+
+ @Override
+ public Intent getDataManagementIntent(String transport)
+ throws RemoteException {
+ return getDataManagementIntentForUser(binderGetCallingUserId(), transport);
+ }
+
/** Supply the manage-data intent for the given transport. */
@Nullable
public Intent getDataManagementIntent(@UserIdInt int userId, String transportName) {
@@ -494,6 +1208,13 @@
: userBackupManagerService.getDataManagementIntent(transportName);
}
+ @Override
+ public CharSequence getDataManagementLabelForUser(int userId, String transport)
+ throws RemoteException {
+ return isUserReadyForBackup(userId) ? getDataManagementLabel(userId, transport)
+ : null;
+ }
+
/**
* Supply the menu label for affordances that fire the manage-data intent for the given
* transport.
@@ -508,43 +1229,76 @@
: userBackupManagerService.getDataManagementLabel(transportName);
}
- // ---------------------------------------------
- // SETTINGS OPERATIONS
- // ---------------------------------------------
-
- /** Enable/disable the backup service. This is user-configurable via backup settings. */
- public void setBackupEnabled(@UserIdInt int userId, boolean enable) {
- UserBackupManagerService userBackupManagerService =
- getServiceForUserIfCallerHasPermission(userId, "setBackupEnabled()");
-
- if (userBackupManagerService != null) {
- userBackupManagerService.setBackupEnabled(enable);
- }
- }
-
- /** Enable/disable automatic restore of app data at install time. */
- public void setAutoRestore(@UserIdInt int userId, boolean autoRestore) {
- UserBackupManagerService userBackupManagerService =
- getServiceForUserIfCallerHasPermission(userId, "setAutoRestore()");
-
- if (userBackupManagerService != null) {
- userBackupManagerService.setAutoRestore(autoRestore);
- }
+ @Override
+ public IRestoreSession beginRestoreSessionForUser(
+ int userId, String packageName, String transportID) throws RemoteException {
+ return isUserReadyForBackup(userId)
+ ? beginRestoreSession(userId, packageName, transportID) : null;
}
/**
- * Return {@code true} if the backup mechanism is currently enabled, else returns {@code false}.
+ * Begin a restore for the specified package {@code packageName} using the specified transport
+ * {@code transportName}.
*/
- public boolean isBackupEnabled(@UserIdInt int userId) {
+ @Nullable
+ public IRestoreSession beginRestoreSession(
+ @UserIdInt int userId, String packageName, String transportName) {
UserBackupManagerService userBackupManagerService =
- getServiceForUserIfCallerHasPermission(userId, "isBackupEnabled()");
+ getServiceForUserIfCallerHasPermission(userId, "beginRestoreSession()");
- return userBackupManagerService != null && userBackupManagerService.isBackupEnabled();
+ return userBackupManagerService == null
+ ? null
+ : userBackupManagerService.beginRestoreSession(packageName, transportName);
}
- // ---------------------------------------------
- // BACKUP OPERATIONS
- // ---------------------------------------------
+ @Override
+ public void opCompleteForUser(int userId, int token, long result) throws RemoteException {
+ if (isUserReadyForBackup(userId)) {
+ opComplete(userId, token, result);
+ }
+ }
+
+ @Override
+ public void opComplete(int token, long result) throws RemoteException {
+ opCompleteForUser(binderGetCallingUserId(), token, result);
+ }
+
+ /**
+ * Used by a currently-active backup agent to notify the service that it has completed its given
+ * outstanding asynchronous backup/restore operation.
+ */
+ public void opComplete(@UserIdInt int userId, int token, long result) {
+ UserBackupManagerService userBackupManagerService =
+ getServiceForUserIfCallerHasPermission(userId, "opComplete()");
+
+ if (userBackupManagerService != null) {
+ userBackupManagerService.opComplete(token, result);
+ }
+ }
+
+ @Override
+ public long getAvailableRestoreTokenForUser(int userId, String packageName) {
+ return isUserReadyForBackup(userId) ? getAvailableRestoreToken(userId, packageName) : 0;
+ }
+
+ /**
+ * Get the restore-set token for the best-available restore set for this {@code packageName}:
+ * the active set if possible, else the ancestral one. Returns zero if none available.
+ */
+ public long getAvailableRestoreToken(@UserIdInt int userId, String packageName) {
+ UserBackupManagerService userBackupManagerService =
+ getServiceForUserIfCallerHasPermission(userId, "getAvailableRestoreToken()");
+
+ return userBackupManagerService == null
+ ? 0
+ : userBackupManagerService.getAvailableRestoreToken(packageName);
+ }
+
+ @Override
+ public boolean isAppEligibleForBackupForUser(int userId, String packageName) {
+ return isUserReadyForBackup(userId) && isAppEligibleForBackup(userId,
+ packageName);
+ }
/** Checks if the given package {@code packageName} is eligible for backup. */
public boolean isAppEligibleForBackup(@UserIdInt int userId, String packageName) {
@@ -555,6 +1309,11 @@
&& userBackupManagerService.isAppEligibleForBackup(packageName);
}
+ @Override
+ public String[] filterAppsEligibleForBackupForUser(int userId, String[] packages) {
+ return isUserReadyForBackup(userId) ? filterAppsEligibleForBackup(userId, packages) : null;
+ }
+
/**
* Returns from the inputted packages {@code packages}, the ones that are eligible for backup.
*/
@@ -568,17 +1327,20 @@
: userBackupManagerService.filterAppsEligibleForBackup(packages);
}
- /**
- * Run a backup pass immediately for any key-value backup applications that have declared that
- * they have pending updates.
- */
- public void backupNow(@UserIdInt int userId) {
- UserBackupManagerService userBackupManagerService =
- getServiceForUserIfCallerHasPermission(userId, "backupNow()");
-
- if (userBackupManagerService != null) {
- userBackupManagerService.backupNow();
+ @Override
+ public int requestBackupForUser(@UserIdInt int userId, String[] packages, IBackupObserver
+ observer, IBackupManagerMonitor monitor, int flags) throws RemoteException {
+ if (!isUserReadyForBackup(userId)) {
+ return BackupManager.ERROR_BACKUP_NOT_ALLOWED;
}
+ return requestBackup(userId, packages, observer, monitor, flags);
+ }
+
+ @Override
+ public int requestBackup(String[] packages, IBackupObserver observer,
+ IBackupManagerMonitor monitor, int flags) throws RemoteException {
+ return requestBackupForUser(binderGetCallingUserId(), packages,
+ observer, monitor, flags);
}
/**
@@ -599,6 +1361,18 @@
: userBackupManagerService.requestBackup(packages, observer, monitor, flags);
}
+ @Override
+ public void cancelBackupsForUser(@UserIdInt int userId) throws RemoteException {
+ if (isUserReadyForBackup(userId)) {
+ cancelBackups(userId);
+ }
+ }
+
+ @Override
+ public void cancelBackups() throws RemoteException {
+ cancelBackupsForUser(binderGetCallingUserId());
+ }
+
/** Cancel all running backup operations. */
public void cancelBackups(@UserIdInt int userId) {
UserBackupManagerService userBackupManagerService =
@@ -610,200 +1384,81 @@
}
/**
- * Used by the {@link JobScheduler} to run a full backup when conditions are right. The model we
- * use is to perform one app backup per scheduled job execution, and to reschedule the job with
- * zero latency as long as conditions remain right and we still have work to do.
+ * Returns a {@link UserHandle} for the user that has {@code ancestralSerialNumber} as the
+ * serial number of its ancestral work profile or null if there is no {@link
+ * UserBackupManagerService} associated with that user.
*
- * @return Whether ongoing work will continue. The return value here will be passed along as the
- * return value to the callback {@link JobService#onStartJob(JobParameters)}.
+ * <p> The ancestral work profile is set by {@link #setAncestralSerialNumber(long)}
+ * and it corresponds to the profile that was used to restore to the callers profile.
*/
- public boolean beginFullBackup(@UserIdInt int userId, FullBackupJob scheduledJob) {
- UserBackupManagerService userBackupManagerService =
- getServiceForUserIfCallerHasPermission(userId, "beginFullBackup()");
-
- return userBackupManagerService != null
- && userBackupManagerService.beginFullBackup(scheduledJob);
- }
-
- /**
- * Used by the {@link JobScheduler} to end the current full backup task when conditions are no
- * longer met for running the full backup job.
- */
- public void endFullBackup(@UserIdInt int userId) {
- UserBackupManagerService userBackupManagerService =
- getServiceForUserIfCallerHasPermission(userId, "endFullBackup()");
-
- if (userBackupManagerService != null) {
- userBackupManagerService.endFullBackup();
- }
- }
-
- /**
- * Run a full backup pass for the given packages {@code packageNames}. Used by 'adb shell bmgr'.
- */
- public void fullTransportBackup(@UserIdInt int userId, String[] packageNames) {
- UserBackupManagerService userBackupManagerService =
- getServiceForUserIfCallerHasPermission(userId, "fullTransportBackup()");
-
- if (userBackupManagerService != null) {
- userBackupManagerService.fullTransportBackup(packageNames);
- }
- }
-
- // ---------------------------------------------
- // RESTORE OPERATIONS
- // ---------------------------------------------
-
- /**
- * Used to run a restore pass for an application that is being installed. This should only be
- * called from the {@link PackageManager}.
- */
- public void restoreAtInstall(@UserIdInt int userId, String packageName, int token) {
- UserBackupManagerService userBackupManagerService =
- getServiceForUserIfCallerHasPermission(userId, "restoreAtInstall()");
-
- if (userBackupManagerService != null) {
- userBackupManagerService.restoreAtInstall(packageName, token);
- }
- }
-
- /**
- * Begin a restore for the specified package {@code packageName} using the specified transport
- * {@code transportName}.
- */
+ @Override
@Nullable
- public IRestoreSession beginRestoreSession(
- @UserIdInt int userId, String packageName, String transportName) {
- UserBackupManagerService userBackupManagerService =
- getServiceForUserIfCallerHasPermission(userId, "beginRestoreSession()");
+ public UserHandle getUserForAncestralSerialNumber(long ancestralSerialNumber) {
+ if (mGlobalDisable) {
+ return null;
+ }
+ int callingUserId = Binder.getCallingUserHandle().getIdentifier();
+ long oldId = Binder.clearCallingIdentity();
+ final int[] userIds;
+ try {
+ userIds =
+ mContext
+ .getSystemService(UserManager.class)
+ .getProfileIds(callingUserId, false);
+ } finally {
+ Binder.restoreCallingIdentity(oldId);
+ }
- return userBackupManagerService == null
- ? null
- : userBackupManagerService.beginRestoreSession(packageName, transportName);
+ for (int userId : userIds) {
+ UserBackupManagerService userBackupManagerService = mUserServices.get(userId);
+ if (userBackupManagerService != null) {
+ if (userBackupManagerService.getAncestralSerialNumber() == ancestralSerialNumber) {
+ return UserHandle.of(userId);
+ }
+ }
+ }
+
+ return null;
}
/**
- * Get the restore-set token for the best-available restore set for this {@code packageName}:
- * the active set if possible, else the ancestral one. Returns zero if none available.
+ * Sets the ancestral work profile for the calling user.
+ *
+ * <p> The ancestral work profile corresponds to the profile that was used to restore to the
+ * callers profile.
*/
- public long getAvailableRestoreToken(@UserIdInt int userId, String packageName) {
- UserBackupManagerService userBackupManagerService =
- getServiceForUserIfCallerHasPermission(userId, "getAvailableRestoreToken()");
-
- return userBackupManagerService == null
- ? 0
- : userBackupManagerService.getAvailableRestoreToken(packageName);
- }
-
- // ---------------------------------------------
- // ADB BACKUP/RESTORE OPERATIONS
- // ---------------------------------------------
-
- /** Sets the backup password used when running adb backup. */
- public boolean setBackupPassword(String currentPassword, String newPassword) {
+ @Override
+ public void setAncestralSerialNumber(long ancestralSerialNumber) {
+ if (mGlobalDisable) {
+ return;
+ }
UserBackupManagerService userBackupManagerService =
getServiceForUserIfCallerHasPermission(
- UserHandle.USER_SYSTEM, "setBackupPassword()");
-
- return userBackupManagerService != null
- && userBackupManagerService.setBackupPassword(currentPassword, newPassword);
- }
-
- /** Returns {@code true} if adb backup was run with a password, else returns {@code false}. */
- public boolean hasBackupPassword() {
- UserBackupManagerService userBackupManagerService =
- getServiceForUserIfCallerHasPermission(
- UserHandle.USER_SYSTEM, "hasBackupPassword()");
-
- return userBackupManagerService != null && userBackupManagerService.hasBackupPassword();
- }
-
- /**
- * Used by 'adb backup' to run a backup pass for packages {@code packageNames} supplied via the
- * command line, writing the resulting data stream to the supplied {@code fd}. This method is
- * synchronous and does not return to the caller until the backup has been completed. It
- * requires on-screen confirmation by the user.
- */
- public void adbBackup(
- @UserIdInt int userId,
- ParcelFileDescriptor fd,
- boolean includeApks,
- boolean includeObbs,
- boolean includeShared,
- boolean doWidgets,
- boolean doAllApps,
- boolean includeSystem,
- boolean doCompress,
- boolean doKeyValue,
- String[] packageNames) {
- UserBackupManagerService userBackupManagerService =
- getServiceForUserIfCallerHasPermission(userId, "adbBackup()");
+ Binder.getCallingUserHandle().getIdentifier(),
+ "setAncestralSerialNumber()");
if (userBackupManagerService != null) {
- userBackupManagerService.adbBackup(
- fd,
- includeApks,
- includeObbs,
- includeShared,
- doWidgets,
- doAllApps,
- includeSystem,
- doCompress,
- doKeyValue,
- packageNames);
+ userBackupManagerService.setAncestralSerialNumber(ancestralSerialNumber);
}
}
- /**
- * Used by 'adb restore' to run a restore pass reading from the supplied {@code fd}. This method
- * is synchronous and does not return to the caller until the restore has been completed. It
- * requires on-screen confirmation by the user.
- */
- public void adbRestore(@UserIdInt int userId, ParcelFileDescriptor fd) {
- UserBackupManagerService userBackupManagerService =
- getServiceForUserIfCallerHasPermission(userId, "adbRestore()");
-
- if (userBackupManagerService != null) {
- userBackupManagerService.adbRestore(fd);
- }
- }
-
- /**
- * Confirm that the previously requested adb backup/restore operation can proceed. This is used
- * to require a user-facing disclosure about the operation.
- */
- public void acknowledgeAdbBackupOrRestore(
- @UserIdInt int userId,
- int token,
- boolean allow,
- String currentPassword,
- String encryptionPassword,
- IFullBackupRestoreObserver observer) {
- UserBackupManagerService userBackupManagerService =
- getServiceForUserIfCallerHasPermission(userId, "acknowledgeAdbBackupOrRestore()");
-
- if (userBackupManagerService != null) {
- userBackupManagerService.acknowledgeAdbBackupOrRestore(
- token, allow, currentPassword, encryptionPassword, observer);
- }
- }
-
- // ---------------------------------------------
- // SERVICE OPERATIONS
- // ---------------------------------------------
-
- /** Prints service state for 'dumpsys backup'. */
+ @Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) {
return;
}
+ int userId = binderGetCallingUserId();
+ if (!isUserReadyForBackup(userId)) {
+ pw.println("Inactive");
+ return;
+ }
if (args != null) {
for (String arg : args) {
if ("users".equals(arg.toLowerCase())) {
pw.print(DUMP_RUNNING_USERS_MESSAGE);
- for (int i = 0; i < mServiceUsers.size(); i++) {
- pw.print(" " + mServiceUsers.keyAt(i));
+ for (int i = 0; i < mUserServices.size(); i++) {
+ pw.print(" " + mUserServices.keyAt(i));
}
pw.println();
return;
@@ -819,31 +1474,103 @@
}
}
+ /**
+ * Used by the {@link JobScheduler} to run a full backup when conditions are right. The model we
+ * use is to perform one app backup per scheduled job execution, and to reschedule the job with
+ * zero latency as long as conditions remain right and we still have work to do.
+ *
+ * @return Whether ongoing work will continue. The return value here will be passed along as the
+ * return value to the callback {@link JobService#onStartJob(JobParameters)}.
+ */
+ public boolean beginFullBackup(@UserIdInt int userId, FullBackupJob scheduledJob) {
+ if (!isUserReadyForBackup(userId)) {
+ return false;
+ }
+ UserBackupManagerService userBackupManagerService =
+ getServiceForUserIfCallerHasPermission(userId, "beginFullBackup()");
+
+ return userBackupManagerService != null
+ && userBackupManagerService.beginFullBackup(scheduledJob);
+ }
+
+ /**
+ * Used by the {@link JobScheduler} to end the current full backup task when conditions are no
+ * longer met for running the full backup job.
+ */
+ public void endFullBackup(@UserIdInt int userId) {
+ if (!isUserReadyForBackup(userId)) {
+ return;
+ }
+ UserBackupManagerService userBackupManagerService =
+ getServiceForUserIfCallerHasPermission(userId, "endFullBackup()");
+
+ if (userBackupManagerService != null) {
+ userBackupManagerService.endFullBackup();
+ }
+ }
+
+ /**
+ * Returns the {@link UserBackupManagerService} instance for the specified user {@code userId}.
+ * If the user is not registered with the service (either the user is locked or not eligible for
+ * the backup service) then return {@code null}.
+ *
+ * @param userId The id of the user to retrieve its instance of {@link
+ * UserBackupManagerService}.
+ * @param caller A {@link String} identifying the caller for logging purposes.
+ * @throws SecurityException if {@code userId} is different from the calling user id and the
+ * caller does NOT have the android.permission.INTERACT_ACROSS_USERS_FULL permission.
+ */
+ @Nullable
+ @VisibleForTesting
+ UserBackupManagerService getServiceForUserIfCallerHasPermission(
+ @UserIdInt int userId, String caller) {
+ enforceCallingPermissionOnUserId(userId, caller);
+ UserBackupManagerService userBackupManagerService = mUserServices.get(userId);
+ if (userBackupManagerService == null) {
+ Slog.w(TAG, "Called " + caller + " for unknown user: " + userId);
+ }
+ return userBackupManagerService;
+ }
+
+ /**
+ * If {@code userId} is different from the calling user id, then the caller must hold the
+ * android.permission.INTERACT_ACROSS_USERS_FULL permission.
+ *
+ * @param userId User id on which the backup operation is being requested.
+ * @param message A message to include in the exception if it is thrown.
+ */
+ void enforceCallingPermissionOnUserId(@UserIdInt int userId, String message) {
+ if (Binder.getCallingUserHandle().getIdentifier() != userId) {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.INTERACT_ACROSS_USERS_FULL, message);
+ }
+ }
+
/** Implementation to receive lifecycle event callbacks for system services. */
public static class Lifecycle extends SystemService {
public Lifecycle(Context context) {
- this(context, new Trampoline(context));
+ this(context, new BackupManagerService(context));
}
@VisibleForTesting
- Lifecycle(Context context, Trampoline trampoline) {
+ Lifecycle(Context context, BackupManagerService backupManagerService) {
super(context);
- Trampoline.sInstance = trampoline;
+ sInstance = backupManagerService;
}
@Override
public void onStart() {
- publishService(Context.BACKUP_SERVICE, Trampoline.sInstance);
+ publishService(Context.BACKUP_SERVICE, BackupManagerService.sInstance);
}
@Override
public void onUnlockUser(int userId) {
- Trampoline.sInstance.onUnlockUser(userId);
+ sInstance.onUnlockUser(userId);
}
@Override
public void onStopUser(int userId) {
- Trampoline.sInstance.onStopUser(userId);
+ sInstance.onStopUser(userId);
}
@VisibleForTesting
diff --git a/services/backup/java/com/android/server/backup/FullBackupJob.java b/services/backup/java/com/android/server/backup/FullBackupJob.java
index 19a8543..0bb25e3 100644
--- a/services/backup/java/com/android/server/backup/FullBackupJob.java
+++ b/services/backup/java/com/android/server/backup/FullBackupJob.java
@@ -91,7 +91,7 @@
mParamsForUser.put(userId, params);
}
- Trampoline service = Trampoline.getInstance();
+ BackupManagerService service = BackupManagerService.getInstance();
return service.beginFullBackup(userId, this);
}
@@ -105,7 +105,7 @@
}
}
- Trampoline service = Trampoline.getInstance();
+ BackupManagerService service = BackupManagerService.getInstance();
service.endFullBackup(userId);
return false;
diff --git a/services/backup/java/com/android/server/backup/KeyValueBackupJob.java b/services/backup/java/com/android/server/backup/KeyValueBackupJob.java
index 7b5dbd7..058dcae 100644
--- a/services/backup/java/com/android/server/backup/KeyValueBackupJob.java
+++ b/services/backup/java/com/android/server/backup/KeyValueBackupJob.java
@@ -144,7 +144,7 @@
}
// Time to run a key/value backup!
- Trampoline service = Trampoline.getInstance();
+ BackupManagerService service = BackupManagerService.getInstance();
try {
service.backupNowForUser(userId);
} catch (RemoteException e) {}
diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java
deleted file mode 100644
index 59d9c0e..0000000
--- a/services/backup/java/com/android/server/backup/Trampoline.java
+++ /dev/null
@@ -1,868 +0,0 @@
-/*
- * Copyright (C) 2014 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.backup;
-
-import static com.android.internal.util.Preconditions.checkNotNull;
-import static com.android.server.backup.BackupManagerService.TAG;
-
-import static java.util.Collections.emptySet;
-
-import android.Manifest;
-import android.annotation.Nullable;
-import android.annotation.UserIdInt;
-import android.app.admin.DevicePolicyManager;
-import android.app.backup.BackupManager;
-import android.app.backup.IBackupManager;
-import android.app.backup.IBackupManagerMonitor;
-import android.app.backup.IBackupObserver;
-import android.app.backup.IFullBackupRestoreObserver;
-import android.app.backup.IRestoreSession;
-import android.app.backup.ISelectBackupTransportCallback;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Binder;
-import android.os.FileUtils;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.IBinder;
-import android.os.ParcelFileDescriptor;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.SystemProperties;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.util.Slog;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.DumpUtils;
-import com.android.server.SystemConfig;
-import com.android.server.backup.utils.RandomAccessFileUtils;
-
-import java.io.File;
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.util.Set;
-
-/**
- * A proxy to the {@link BackupManagerService} implementation.
- *
- * <p>This is an external interface to the {@link BackupManagerService} which is being accessed via
- * published binder {@link BackupManagerService.Lifecycle}. This lets us turn down the heavy
- * implementation object on the fly without disturbing binders that have been cached somewhere in
- * the system.
- *
- * <p>Trampoline determines whether the backup service is available. It can be disabled in the
- * following two ways:
- *
- * <ul>
- * <li>Temporary - create the file {@link #BACKUP_SUPPRESS_FILENAME}, or
- * <li>Permanent - set the system property {@link #BACKUP_DISABLE_PROPERTY} to true.
- * </ul>
- *
- * Temporary disabling is controlled by {@link #setBackupServiceActive(int, boolean)} through
- * privileged callers (currently {@link DevicePolicyManager}). This is called on {@link
- * UserHandle#USER_SYSTEM} and disables backup for all users.
- */
-public class Trampoline extends IBackupManager.Stub {
- /**
- * Name of file that disables the backup service. If this file exists, then backup is disabled
- * for all users.
- */
- private static final String BACKUP_SUPPRESS_FILENAME = "backup-suppress";
-
- /**
- * Name of file for non-system users that enables the backup service for the user. Backup is
- * disabled by default in non-system users.
- */
- private static final String BACKUP_ACTIVATED_FILENAME = "backup-activated";
-
- /**
- * Name of file for non-system users that remembers whether backup was explicitly activated or
- * deactivated with a call to setBackupServiceActive.
- */
- private static final String REMEMBER_ACTIVATED_FILENAME = "backup-remember-activated";
-
- // Product-level suppression of backup/restore.
- private static final String BACKUP_DISABLE_PROPERTY = "ro.backup.disable";
-
- private static final String BACKUP_THREAD = "backup";
-
- static Trampoline sInstance;
-
- static Trampoline getInstance() {
- return checkNotNull(sInstance);
- }
-
- private final Context mContext;
- private final UserManager mUserManager;
-
- private final boolean mGlobalDisable;
- // Lock to write backup suppress files.
- // TODD(b/121198006): remove this object and synchronized all methods on "this".
- private final Object mStateLock = new Object();
-
- // TODO: This is not marked as final because of test code. Since we'll merge BMS and Trampoline,
- // it doesn't make sense to refactor for final. It's never null.
- @VisibleForTesting
- protected volatile BackupManagerService mService;
- private final Handler mHandler;
- private final Set<ComponentName> mTransportWhitelist;
-
- private final BroadcastReceiver mUserRemovedReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
- int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
- if (userId > 0) { // for only non system users
- mHandler.post(() -> onRemovedNonSystemUser(userId));
- }
- }
- }
- };
-
- public Trampoline(Context context) {
- mContext = context;
- mGlobalDisable = isBackupDisabled();
- HandlerThread handlerThread =
- new HandlerThread(BACKUP_THREAD, Process.THREAD_PRIORITY_BACKGROUND);
- handlerThread.start();
- mHandler = new Handler(handlerThread.getLooper());
- mUserManager = UserManager.get(context);
- mService = new BackupManagerService(mContext, this);
- Set<ComponentName> transportWhitelist =
- SystemConfig.getInstance().getBackupTransportWhitelist();
- mTransportWhitelist = (transportWhitelist == null) ? emptySet() : transportWhitelist;
- mContext.registerReceiver(
- mUserRemovedReceiver, new IntentFilter(Intent.ACTION_USER_REMOVED));
- }
-
- // TODO: Remove this when we implement DI by injecting in the construtor.
- @VisibleForTesting
- Handler getBackupHandler() {
- return mHandler;
- }
-
- protected boolean isBackupDisabled() {
- return SystemProperties.getBoolean(BACKUP_DISABLE_PROPERTY, false);
- }
-
- protected int binderGetCallingUserId() {
- return Binder.getCallingUserHandle().getIdentifier();
- }
-
- protected int binderGetCallingUid() {
- return Binder.getCallingUid();
- }
-
- /** Stored in the system user's directory. */
- protected File getSuppressFileForSystemUser() {
- return new File(UserBackupManagerFiles.getBaseStateDir(UserHandle.USER_SYSTEM),
- BACKUP_SUPPRESS_FILENAME);
- }
-
- /** Stored in the system user's directory and the file is indexed by the user it refers to. */
- protected File getRememberActivatedFileForNonSystemUser(int userId) {
- return UserBackupManagerFiles.getStateFileInSystemDir(REMEMBER_ACTIVATED_FILENAME, userId);
- }
-
- /** Stored in the system user's directory and the file is indexed by the user it refers to. */
- protected File getActivatedFileForNonSystemUser(int userId) {
- return UserBackupManagerFiles.getStateFileInSystemDir(BACKUP_ACTIVATED_FILENAME, userId);
- }
-
- /**
- * Remove backup state for non system {@code userId} when the user is removed from the device.
- * For non system users, backup state is stored in both the user's own dir and the system dir.
- * When the user is removed, the user's own dir gets removed by the OS. This method ensures that
- * the part of the user backup state which is in the system dir also gets removed.
- */
- private void onRemovedNonSystemUser(int userId) {
- Slog.i(TAG, "Removing state for non system user " + userId);
- File dir = UserBackupManagerFiles.getStateDirInSystemDir(userId);
- if (!FileUtils.deleteContentsAndDir(dir)) {
- Slog.w(TAG, "Failed to delete state dir for removed user: " + userId);
- }
- }
-
- // TODO (b/124359804) move to util method in FileUtils
- private void createFile(File file) throws IOException {
- if (file.exists()) {
- return;
- }
-
- file.getParentFile().mkdirs();
- if (!file.createNewFile()) {
- Slog.w(TAG, "Failed to create file " + file.getPath());
- }
- }
-
- // TODO (b/124359804) move to util method in FileUtils
- private void deleteFile(File file) {
- if (!file.exists()) {
- return;
- }
-
- if (!file.delete()) {
- Slog.w(TAG, "Failed to delete file " + file.getPath());
- }
- }
-
- /**
- * Deactivates the backup service for user {@code userId}. If this is the system user, it
- * creates a suppress file which disables backup for all users. If this is a non-system user, it
- * only deactivates backup for that user by deleting its activate file.
- */
- @GuardedBy("mStateLock")
- private void deactivateBackupForUserLocked(int userId) throws IOException {
- if (userId == UserHandle.USER_SYSTEM) {
- createFile(getSuppressFileForSystemUser());
- } else {
- deleteFile(getActivatedFileForNonSystemUser(userId));
- }
- }
-
- /**
- * Enables the backup service for user {@code userId}. If this is the system user, it deletes
- * the suppress file. If this is a non-system user, it creates the user's activate file. Note,
- * deleting the suppress file does not automatically enable backup for non-system users, they
- * need their own activate file in order to participate in the service.
- */
- @GuardedBy("mStateLock")
- private void activateBackupForUserLocked(int userId) throws IOException {
- if (userId == UserHandle.USER_SYSTEM) {
- deleteFile(getSuppressFileForSystemUser());
- } else {
- createFile(getActivatedFileForNonSystemUser(userId));
- }
- }
-
- // This method should not perform any I/O (e.g. do not call isBackupActivatedForUser),
- // it's used in multiple places where I/O waits would cause system lock-ups.
- private boolean isUserReadyForBackup(int userId) {
- return mService.isAbleToServeUser(userId);
- }
-
- /**
- * Backup is activated for the system user if the suppress file does not exist. Backup is
- * activated for non-system users if the suppress file does not exist AND the user's activated
- * file exists.
- */
- private boolean isBackupActivatedForUser(int userId) {
- if (getSuppressFileForSystemUser().exists()) {
- return false;
- }
-
- return userId == UserHandle.USER_SYSTEM
- || getActivatedFileForNonSystemUser(userId).exists();
- }
-
- protected Context getContext() {
- return mContext;
- }
-
- protected UserManager getUserManager() {
- return mUserManager;
- }
-
- protected void postToHandler(Runnable runnable) {
- mHandler.post(runnable);
- }
-
- /**
- * Called from {@link BackupManagerService.Lifecycle} when a user {@code userId} is unlocked.
- * Starts the backup service for this user if backup is active for this user. Offloads work onto
- * the handler thread {@link #mHandlerThread} to keep unlock time low since backup is not
- * essential for device functioning.
- */
- void onUnlockUser(int userId) {
- postToHandler(() -> startServiceForUser(userId));
- }
-
- private void startServiceForUser(int userId) {
- // We know that the user is unlocked here because it is called from setBackupServiceActive
- // and unlockUser which have these guarantees. So we can check if the file exists.
- if (mGlobalDisable) {
- Slog.i(TAG, "Backup service not supported");
- return;
- }
- if (!isBackupActivatedForUser(userId)) {
- Slog.i(TAG, "Backup not activated for user " + userId);
- return;
- }
- Slog.i(TAG, "Starting service for user: " + userId);
- mService.startServiceForUser(userId, mTransportWhitelist);
- }
-
- /**
- * Called from {@link BackupManagerService.Lifecycle} when a user {@code userId} is stopped.
- * Offloads work onto the handler thread {@link #mHandlerThread} to keep stopping time low.
- */
- void onStopUser(int userId) {
- postToHandler(
- () -> {
- if (!mGlobalDisable) {
- Slog.i(TAG, "Stopping service for user: " + userId);
- mService.stopServiceForUser(userId);
- }
- });
- }
-
- /** Returns {@link UserBackupManagerService} for user {@code userId}. */
- @Nullable
- public UserBackupManagerService getUserService(int userId) {
- return mService.getUserServices().get(userId);
- }
-
- /**
- * The system user and managed profiles can only be acted on by callers in the system or root
- * processes. Other users can be acted on by callers who have both android.permission.BACKUP and
- * android.permission.INTERACT_ACROSS_USERS_FULL permissions.
- */
- private void enforcePermissionsOnUser(int userId) throws SecurityException {
- boolean isRestrictedUser =
- userId == UserHandle.USER_SYSTEM
- || getUserManager().getUserInfo(userId).isManagedProfile();
-
- if (isRestrictedUser) {
- int caller = binderGetCallingUid();
- if (caller != Process.SYSTEM_UID && caller != Process.ROOT_UID) {
- throw new SecurityException("No permission to configure backup activity");
- }
- } else {
- mContext.enforceCallingOrSelfPermission(
- Manifest.permission.BACKUP, "No permission to configure backup activity");
- mContext.enforceCallingOrSelfPermission(
- Manifest.permission.INTERACT_ACROSS_USERS_FULL,
- "No permission to configure backup activity");
- }
- }
-
- /**
- * Only privileged callers should be changing the backup state. Deactivating backup in the
- * system user also deactivates backup in all users. We are not guaranteed that {@code userId}
- * is unlocked at this point yet, so handle both cases.
- */
- public void setBackupServiceActive(int userId, boolean makeActive) {
- enforcePermissionsOnUser(userId);
-
- // In Q, backup is OFF by default for non-system users. In the future, we will change that
- // to ON unless backup was explicitly deactivated with a (permissioned) call to
- // setBackupServiceActive.
- // Therefore, remember this for use in the future. Basically the default in the future will
- // be: rememberFile.exists() ? rememberFile.value() : ON
- // Note that this has to be done right after the permission checks and before any other
- // action since we need to remember that a permissioned call was made irrespective of
- // whether the call changes the state or not.
- if (userId != UserHandle.USER_SYSTEM) {
- try {
- File rememberFile = getRememberActivatedFileForNonSystemUser(userId);
- createFile(rememberFile);
- RandomAccessFileUtils.writeBoolean(rememberFile, makeActive);
- } catch (IOException e) {
- Slog.e(TAG, "Unable to persist backup service activity", e);
- }
- }
-
- if (mGlobalDisable) {
- Slog.i(TAG, "Backup service not supported");
- return;
- }
-
- synchronized (mStateLock) {
- Slog.i(TAG, "Making backup " + (makeActive ? "" : "in") + "active");
- if (makeActive) {
- try {
- activateBackupForUserLocked(userId);
- } catch (IOException e) {
- Slog.e(TAG, "Unable to persist backup service activity");
- }
-
- // If the user is unlocked, we can start the backup service for it. Otherwise we
- // will start the service when the user is unlocked as part of its unlock callback.
- if (getUserManager().isUserUnlocked(userId)) {
- // Clear calling identity as initialization enforces the system identity but we
- // can be coming from shell.
- long oldId = Binder.clearCallingIdentity();
- try {
- startServiceForUser(userId);
- } finally {
- Binder.restoreCallingIdentity(oldId);
- }
- }
- } else {
- try {
- //TODO(b/121198006): what if this throws an exception?
- deactivateBackupForUserLocked(userId);
- } catch (IOException e) {
- Slog.e(TAG, "Unable to persist backup service inactivity");
- }
- //TODO(b/121198006): loop through active users that have work profile and
- // stop them as well.
- onStopUser(userId);
- }
- }
- }
-
- // IBackupManager binder API
-
- /**
- * Querying activity state of backup service.
- *
- * @param userId The user in which the activity state of backup service is queried.
- * @return true if the service is active.
- */
- @Override
- public boolean isBackupServiceActive(int userId) {
- synchronized (mStateLock) {
- return !mGlobalDisable && isBackupActivatedForUser(userId);
- }
- }
-
- @Override
- public void dataChangedForUser(int userId, String packageName) throws RemoteException {
- if (isUserReadyForBackup(userId)) {
- mService.dataChanged(userId, packageName);
- }
- }
-
- @Override
- public void dataChanged(String packageName) throws RemoteException {
- dataChangedForUser(binderGetCallingUserId(), packageName);
- }
-
- @Override
- public void initializeTransportsForUser(
- int userId, String[] transportNames, IBackupObserver observer) throws RemoteException {
- if (isUserReadyForBackup(userId)) {
- mService.initializeTransports(userId, transportNames, observer);
- }
- }
-
- @Override
- public void clearBackupDataForUser(int userId, String transportName, String packageName)
- throws RemoteException {
- if (isUserReadyForBackup(userId)) {
- mService.clearBackupData(userId, transportName, packageName);
- }
- }
-
- @Override
- public void clearBackupData(String transportName, String packageName)
- throws RemoteException {
- clearBackupDataForUser(binderGetCallingUserId(), transportName, packageName);
- }
-
- @Override
- public void agentConnectedForUser(int userId, String packageName, IBinder agent)
- throws RemoteException {
- if (isUserReadyForBackup(userId)) {
- mService.agentConnected(userId, packageName, agent);
- }
- }
-
- @Override
- public void agentConnected(String packageName, IBinder agent) throws RemoteException {
- agentConnectedForUser(binderGetCallingUserId(), packageName, agent);
- }
-
- @Override
- public void agentDisconnectedForUser(int userId, String packageName) throws RemoteException {
- if (isUserReadyForBackup(userId)) {
- mService.agentDisconnected(userId, packageName);
- }
- }
-
- @Override
- public void agentDisconnected(String packageName) throws RemoteException {
- agentDisconnectedForUser(binderGetCallingUserId(), packageName);
- }
-
- @Override
- public void restoreAtInstallForUser(int userId, String packageName, int token)
- throws RemoteException {
- if (isUserReadyForBackup(userId)) {
- mService.restoreAtInstall(userId, packageName, token);
- }
- }
-
- @Override
- public void restoreAtInstall(String packageName, int token) throws RemoteException {
- restoreAtInstallForUser(binderGetCallingUserId(), packageName, token);
- }
-
- @Override
- public void setBackupEnabledForUser(@UserIdInt int userId, boolean isEnabled)
- throws RemoteException {
- if (isUserReadyForBackup(userId)) {
- mService.setBackupEnabled(userId, isEnabled);
- }
- }
-
- @Override
- public void setBackupEnabled(boolean isEnabled) throws RemoteException {
- setBackupEnabledForUser(binderGetCallingUserId(), isEnabled);
- }
-
- @Override
- public void setAutoRestoreForUser(int userId, boolean doAutoRestore) throws RemoteException {
- if (isUserReadyForBackup(userId)) {
- mService.setAutoRestore(userId, doAutoRestore);
- }
- }
-
- @Override
- public void setAutoRestore(boolean doAutoRestore) throws RemoteException {
- setAutoRestoreForUser(binderGetCallingUserId(), doAutoRestore);
- }
-
- @Override
- public boolean isBackupEnabledForUser(@UserIdInt int userId) throws RemoteException {
- return isUserReadyForBackup(userId) && mService.isBackupEnabled(userId);
- }
-
- @Override
- public boolean isBackupEnabled() throws RemoteException {
- return isBackupEnabledForUser(binderGetCallingUserId());
- }
-
- @Override
- public boolean setBackupPassword(String currentPw, String newPw) throws RemoteException {
- int userId = binderGetCallingUserId();
- return (isUserReadyForBackup(userId)) && mService.setBackupPassword(currentPw, newPw);
- }
-
- @Override
- public boolean hasBackupPassword() throws RemoteException {
- int userId = binderGetCallingUserId();
- return (isUserReadyForBackup(userId)) && mService.hasBackupPassword();
- }
-
- @Override
- public void backupNowForUser(@UserIdInt int userId) throws RemoteException {
- if (isUserReadyForBackup(userId)) {
- mService.backupNow(userId);
- }
- }
-
- @Override
- public void backupNow() throws RemoteException {
- backupNowForUser(binderGetCallingUserId());
- }
-
- public void adbBackup(@UserIdInt int userId, ParcelFileDescriptor fd,
- boolean includeApks, boolean includeObbs, boolean includeShared, boolean doWidgets,
- boolean allApps, boolean allIncludesSystem, boolean doCompress, boolean doKeyValue,
- String[] packageNames) throws RemoteException {
- if (isUserReadyForBackup(userId)) {
- mService.adbBackup(userId, fd, includeApks, includeObbs, includeShared, doWidgets,
- allApps, allIncludesSystem, doCompress, doKeyValue, packageNames);
- }
- }
-
- @Override
- public void fullTransportBackupForUser(int userId, String[] packageNames)
- throws RemoteException {
- if (isUserReadyForBackup(userId)) {
- mService.fullTransportBackup(userId, packageNames);
- }
- }
-
- @Override
- public void adbRestore(@UserIdInt int userId, ParcelFileDescriptor fd) throws RemoteException {
- if (isUserReadyForBackup(userId)) {
- mService.adbRestore(userId, fd);
- }
- }
-
- @Override
- public void acknowledgeFullBackupOrRestoreForUser(
- int userId,
- int token,
- boolean allow,
- String curPassword,
- String encryptionPassword,
- IFullBackupRestoreObserver observer)
- throws RemoteException {
- if (isUserReadyForBackup(userId)) {
- mService.acknowledgeAdbBackupOrRestore(userId, token, allow,
- curPassword, encryptionPassword, observer);
- }
- }
-
- @Override
- public void acknowledgeFullBackupOrRestore(int token, boolean allow, String curPassword,
- String encryptionPassword, IFullBackupRestoreObserver observer)
- throws RemoteException {
- acknowledgeFullBackupOrRestoreForUser(
- binderGetCallingUserId(), token, allow, curPassword, encryptionPassword, observer);
- }
-
-
- @Override
- public String getCurrentTransportForUser(int userId) throws RemoteException {
- return (isUserReadyForBackup(userId)) ? mService.getCurrentTransport(userId) : null;
- }
-
- @Override
- public String getCurrentTransport() throws RemoteException {
- return getCurrentTransportForUser(binderGetCallingUserId());
- }
-
- /**
- * Returns the {@link ComponentName} of the host service of the selected transport or
- * {@code null} if no transport selected or if the transport selected is not registered.
- */
- @Override
- @Nullable
- public ComponentName getCurrentTransportComponentForUser(int userId) {
- return (isUserReadyForBackup(userId))
- ? mService.getCurrentTransportComponent(userId) : null;
- }
-
- @Override
- public String[] listAllTransportsForUser(int userId) throws RemoteException {
- return (isUserReadyForBackup(userId)) ? mService.listAllTransports(userId) : null;
- }
-
- @Override
- public String[] listAllTransports() throws RemoteException {
- return listAllTransportsForUser(binderGetCallingUserId());
- }
-
- @Override
- public ComponentName[] listAllTransportComponentsForUser(int userId) throws RemoteException {
- return (isUserReadyForBackup(userId))
- ? mService.listAllTransportComponents(userId) : null;
- }
-
- @Override
- public String[] getTransportWhitelist() {
- int userId = binderGetCallingUserId();
- if (!isUserReadyForBackup(userId)) {
- return null;
- }
- // No permission check, intentionally.
- String[] whitelistedTransports = new String[mTransportWhitelist.size()];
- int i = 0;
- for (ComponentName component : mTransportWhitelist) {
- whitelistedTransports[i] = component.flattenToShortString();
- i++;
- }
- return whitelistedTransports;
- }
-
- @Override
- public void updateTransportAttributesForUser(
- int userId,
- ComponentName transportComponent,
- String name,
- @Nullable Intent configurationIntent,
- String currentDestinationString,
- @Nullable Intent dataManagementIntent,
- CharSequence dataManagementLabel) {
- if (isUserReadyForBackup(userId)) {
- mService.updateTransportAttributes(
- userId,
- transportComponent,
- name,
- configurationIntent,
- currentDestinationString,
- dataManagementIntent,
- dataManagementLabel);
- }
- }
-
- @Override
- public String selectBackupTransportForUser(int userId, String transport)
- throws RemoteException {
- return (isUserReadyForBackup(userId))
- ? mService.selectBackupTransport(userId, transport) : null;
- }
-
- @Override
- public String selectBackupTransport(String transport) throws RemoteException {
- return selectBackupTransportForUser(binderGetCallingUserId(), transport);
- }
-
- @Override
- public void selectBackupTransportAsyncForUser(int userId, ComponentName transport,
- ISelectBackupTransportCallback listener) throws RemoteException {
- if (isUserReadyForBackup(userId)) {
- mService.selectBackupTransportAsync(userId, transport, listener);
- } else {
- if (listener != null) {
- try {
- listener.onFailure(BackupManager.ERROR_BACKUP_NOT_ALLOWED);
- } catch (RemoteException ex) {
- // ignore
- }
- }
- }
- }
-
- @Override
- public Intent getConfigurationIntentForUser(int userId, String transport)
- throws RemoteException {
- return isUserReadyForBackup(userId) ? mService.getConfigurationIntent(userId, transport)
- : null;
- }
-
- @Override
- public Intent getConfigurationIntent(String transport)
- throws RemoteException {
- return getConfigurationIntentForUser(binderGetCallingUserId(), transport);
- }
-
- @Override
- public String getDestinationStringForUser(int userId, String transport) throws RemoteException {
- return isUserReadyForBackup(userId) ? mService.getDestinationString(userId, transport)
- : null;
- }
-
- @Override
- public String getDestinationString(String transport) throws RemoteException {
- return getDestinationStringForUser(binderGetCallingUserId(), transport);
- }
-
- @Override
- public Intent getDataManagementIntentForUser(int userId, String transport)
- throws RemoteException {
- return isUserReadyForBackup(userId)
- ? mService.getDataManagementIntent(userId, transport) : null;
- }
-
- @Override
- public Intent getDataManagementIntent(String transport)
- throws RemoteException {
- return getDataManagementIntentForUser(binderGetCallingUserId(), transport);
- }
-
- @Override
- public CharSequence getDataManagementLabelForUser(int userId, String transport)
- throws RemoteException {
- return isUserReadyForBackup(userId) ? mService.getDataManagementLabel(userId, transport)
- : null;
- }
-
- @Override
- public IRestoreSession beginRestoreSessionForUser(
- int userId, String packageName, String transportID) throws RemoteException {
- return isUserReadyForBackup(userId) ? mService.beginRestoreSession(userId, packageName,
- transportID) : null;
- }
-
- @Override
- public void opCompleteForUser(int userId, int token, long result) throws RemoteException {
- if (isUserReadyForBackup(userId)) {
- mService.opComplete(userId, token, result);
- }
- }
-
- @Override
- public void opComplete(int token, long result) throws RemoteException {
- opCompleteForUser(binderGetCallingUserId(), token, result);
- }
-
- @Override
- public long getAvailableRestoreTokenForUser(int userId, String packageName) {
- return isUserReadyForBackup(userId) ? mService.getAvailableRestoreToken(userId,
- packageName) : 0;
- }
-
- @Override
- public boolean isAppEligibleForBackupForUser(int userId, String packageName) {
- return isUserReadyForBackup(userId) && mService.isAppEligibleForBackup(userId,
- packageName);
- }
-
- @Override
- public String[] filterAppsEligibleForBackupForUser(int userId, String[] packages) {
- return isUserReadyForBackup(userId) ? mService.filterAppsEligibleForBackup(userId,
- packages) : null;
- }
-
- @Override
- public int requestBackupForUser(@UserIdInt int userId, String[] packages, IBackupObserver
- observer, IBackupManagerMonitor monitor, int flags) throws RemoteException {
- if (!isUserReadyForBackup(userId)) {
- return BackupManager.ERROR_BACKUP_NOT_ALLOWED;
- }
- return mService.requestBackup(userId, packages, observer, monitor, flags);
- }
-
- @Override
- public int requestBackup(String[] packages, IBackupObserver observer,
- IBackupManagerMonitor monitor, int flags) throws RemoteException {
- return requestBackupForUser(binderGetCallingUserId(), packages,
- observer, monitor, flags);
- }
-
- @Override
- public void cancelBackupsForUser(@UserIdInt int userId) throws RemoteException {
- if (isUserReadyForBackup(userId)) {
- mService.cancelBackups(userId);
- }
- }
-
- @Override
- public void cancelBackups() throws RemoteException {
- cancelBackupsForUser(binderGetCallingUserId());
- }
-
- @Override
- @Nullable public UserHandle getUserForAncestralSerialNumber(long ancestralSerialNumber) {
- if (mGlobalDisable) {
- return null;
- }
- return mService.getUserForAncestralSerialNumber(ancestralSerialNumber);
- }
-
- @Override
- public void setAncestralSerialNumber(long ancestralSerialNumber) {
- if (!mGlobalDisable) {
- mService.setAncestralSerialNumber(ancestralSerialNumber);
- }
- }
-
- @Override
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
- int userId = binderGetCallingUserId();
- if (isUserReadyForBackup(userId)) {
- mService.dump(fd, pw, args);
- } else {
- pw.println("Inactive");
- }
- }
-
- // Full backup/restore entry points - non-Binder; called directly
- // by the full-backup scheduled job
- /* package */ boolean beginFullBackup(@UserIdInt int userId, FullBackupJob scheduledJob) {
- return (isUserReadyForBackup(userId)) && mService.beginFullBackup(userId, scheduledJob);
- }
-
- /* package */ void endFullBackup(@UserIdInt int userId) {
- if (isUserReadyForBackup(userId)) {
- mService.endFullBackup(userId);
- }
- }
-}
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index d599aab..77888db 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -421,13 +421,13 @@
* Creates an instance of {@link UserBackupManagerService} and initializes state for it. This
* includes setting up the directories where we keep our bookkeeping and transport management.
*
- * @see #createAndInitializeService(int, Context, Trampoline, HandlerThread, File, File,
- * TransportManager)
+ * @see #createAndInitializeService(int, Context, BackupManagerService, HandlerThread, File,
+ * File, TransportManager)
*/
static UserBackupManagerService createAndInitializeService(
@UserIdInt int userId,
Context context,
- Trampoline trampoline,
+ BackupManagerService backupManagerService,
Set<ComponentName> transportWhitelist) {
String currentTransport =
Settings.Secure.getStringForUser(
@@ -455,7 +455,7 @@
return createAndInitializeService(
userId,
context,
- trampoline,
+ backupManagerService,
userBackupThread,
baseStateDir,
dataDir,
@@ -467,7 +467,7 @@
*
* @param userId The user which this service is for.
* @param context The system server context.
- * @param trampoline A reference to the proxy to {@link BackupManagerService}.
+ * @param backupManagerService A reference to the proxy to {@link BackupManagerService}.
* @param userBackupThread The thread running backup/restore operations for the user.
* @param baseStateDir The directory we store the user's persistent bookkeeping data.
* @param dataDir The directory we store the user's temporary staging data.
@@ -478,7 +478,7 @@
public static UserBackupManagerService createAndInitializeService(
@UserIdInt int userId,
Context context,
- Trampoline trampoline,
+ BackupManagerService backupManagerService,
HandlerThread userBackupThread,
File baseStateDir,
File dataDir,
@@ -486,7 +486,7 @@
return new UserBackupManagerService(
userId,
context,
- trampoline,
+ backupManagerService,
userBackupThread,
baseStateDir,
dataDir,
@@ -509,7 +509,7 @@
private UserBackupManagerService(
@UserIdInt int userId,
Context context,
- Trampoline parent,
+ BackupManagerService parent,
HandlerThread userBackupThread,
File baseStateDir,
File dataDir,
@@ -525,8 +525,8 @@
mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
mStorageManager = IStorageManager.Stub.asInterface(ServiceManager.getService("mount"));
- checkNotNull(parent, "trampoline cannot be null");
- mBackupManagerBinder = Trampoline.asInterface(parent.asBinder());
+ checkNotNull(parent, "parent cannot be null");
+ mBackupManagerBinder = BackupManagerService.asInterface(parent.asBinder());
mAgentTimeoutParameters = new
BackupAgentTimeoutParameters(Handler.getMain(), mContext.getContentResolver());
@@ -649,7 +649,8 @@
}
/** Cleans up state when the user of this service is stopped. */
- void tearDownService() {
+ @VisibleForTesting
+ protected void tearDownService() {
mAgentTimeoutParameters.stop();
mConstants.stop();
mContext.getContentResolver().unregisterContentObserver(mSetupObserver);
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 474dbfe..c838c60 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -13,7 +13,6 @@
},
srcs: [
"java/**/*.java",
- ":platformcompat_aidl",
":dumpstate_aidl",
":idmap2_aidl",
":installd_aidl",
@@ -82,11 +81,3 @@
name: "gps_debug.conf",
src: "java/com/android/server/location/gps_debug.conf",
}
-
-filegroup {
- name: "platformcompat_aidl",
- srcs: [
- "java/com/android/server/compat/IPlatformCompat.aidl",
- ],
- path: "java",
-}
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index fede487..9a97ddb 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -172,7 +172,7 @@
final LocalLog mLog = new LocalLog(TAG);
AppOpsManager mAppOps;
- DeviceIdleController.LocalService mLocalDeviceIdleController;
+ DeviceIdleInternal mLocalDeviceIdleController;
private UsageStatsManagerInternal mUsageStatsManagerInternal;
final Object mLock = new Object();
@@ -1594,7 +1594,7 @@
mConstants.start(getContext().getContentResolver());
mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
mLocalDeviceIdleController =
- LocalServices.getService(DeviceIdleController.LocalService.class);
+ LocalServices.getService(DeviceIdleInternal.class);
mUsageStatsManagerInternal =
LocalServices.getService(UsageStatsManagerInternal.class);
mUsageStatsManagerInternal.addAppIdleStateChangeListener(new AppStandbyTracker());
diff --git a/services/core/java/com/android/server/AnimationThread.java b/services/core/java/com/android/server/AnimationThread.java
index c86042b..c607b1e 100644
--- a/services/core/java/com/android/server/AnimationThread.java
+++ b/services/core/java/com/android/server/AnimationThread.java
@@ -21,6 +21,8 @@
import android.os.Handler;
import android.os.Trace;
+import com.android.internal.annotations.VisibleForTesting;
+
/**
* Thread for handling all legacy window animations, or anything that's directly impacting
* animations like starting windows or traversals.
@@ -55,4 +57,20 @@
return sHandler;
}
}
+
+ /**
+ * Disposes current animation thread if it's initialized. Should only be used in tests to set up
+ * a new environment.
+ */
+ @VisibleForTesting
+ public static void dispose() {
+ synchronized (DisplayThread.class) {
+ if (sInstance == null) {
+ return;
+ }
+
+ getHandler().runWithScissors(() -> sInstance.quit(), 0 /* timeout */);
+ sInstance = null;
+ }
+ }
}
diff --git a/services/core/java/com/android/server/BluetoothService.java b/services/core/java/com/android/server/BluetoothService.java
index 112cf08..0bcd937 100644
--- a/services/core/java/com/android/server/BluetoothService.java
+++ b/services/core/java/com/android/server/BluetoothService.java
@@ -53,8 +53,11 @@
@Override
public void onSwitchUser(int userHandle) {
- initialize();
- mBluetoothManagerService.handleOnSwitchUser(userHandle);
+ if (!mInitialized) {
+ initialize();
+ } else {
+ mBluetoothManagerService.handleOnSwitchUser(userHandle);
+ }
}
@Override
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index a303718..62930b0 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -1636,27 +1636,32 @@
}
}
- public class LocalService {
+ private class LocalService implements DeviceIdleInternal {
+ @Override
public void onConstraintStateChanged(IDeviceIdleConstraint constraint, boolean active) {
synchronized (DeviceIdleController.this) {
onConstraintStateChangedLocked(constraint, active);
}
}
+ @Override
public void registerDeviceIdleConstraint(IDeviceIdleConstraint constraint, String name,
@IDeviceIdleConstraint.MinimumState int minState) {
registerDeviceIdleConstraintInternal(constraint, name, minState);
}
+ @Override
public void unregisterDeviceIdleConstraint(IDeviceIdleConstraint constraint) {
unregisterDeviceIdleConstraintInternal(constraint);
}
+ @Override
public void exitIdle(String reason) {
exitIdleInternal(reason);
}
// duration in milliseconds
+ @Override
public void addPowerSaveTempWhitelistApp(int callingUid, String packageName,
long duration, int userId, boolean sync, String reason) {
addPowerSaveTempWhitelistAppInternal(callingUid, packageName, duration,
@@ -1664,26 +1669,31 @@
}
// duration in milliseconds
+ @Override
public void addPowerSaveTempWhitelistAppDirect(int uid, long duration, boolean sync,
String reason) {
addPowerSaveTempWhitelistAppDirectInternal(0, uid, duration, sync, reason);
}
// duration in milliseconds
+ @Override
public long getNotificationWhitelistDuration() {
return mConstants.NOTIFICATION_WHITELIST_DURATION;
}
+ @Override
public void setJobsActive(boolean active) {
DeviceIdleController.this.setJobsActive(active);
}
// Up-call from alarm manager.
+ @Override
public void setAlarmsActive(boolean active) {
DeviceIdleController.this.setAlarmsActive(active);
}
/** Is the app on any of the power save whitelists, whether system or user? */
+ @Override
public boolean isAppOnWhitelist(int appid) {
return DeviceIdleController.this.isAppOnWhitelistInternal(appid);
}
@@ -1694,10 +1704,12 @@
* can change when the list changes, so it needs to be re-acquired when
* {@link PowerManager#ACTION_POWER_SAVE_WHITELIST_CHANGED} is sent.
*/
+ @Override
public int[] getPowerSaveWhitelistUserAppIds() {
return DeviceIdleController.this.getPowerSaveWhitelistUserAppIds();
}
+ @Override
public int[] getPowerSaveTempWhitelistAppIds() {
return DeviceIdleController.this.getAppIdTempWhitelistInternal();
}
@@ -1767,7 +1779,8 @@
return mContext.getSystemService(SensorManager.class);
}
- ConstraintController getConstraintController(Handler handler, LocalService localService) {
+ ConstraintController getConstraintController(Handler handler,
+ DeviceIdleInternal localService) {
if (mContext.getPackageManager()
.hasSystemFeature(PackageManager.FEATURE_LEANBACK_ONLY)) {
return new TvConstraintController(mContext, handler);
@@ -1884,7 +1897,7 @@
mBinderService = new BinderService();
publishBinderService(Context.DEVICE_IDLE_CONTROLLER, mBinderService);
- publishLocalService(LocalService.class, new LocalService());
+ publishLocalService(DeviceIdleInternal.class, new LocalService());
}
@Override
diff --git a/services/core/java/com/android/server/DeviceIdleInternal.java b/services/core/java/com/android/server/DeviceIdleInternal.java
new file mode 100644
index 0000000..1273249
--- /dev/null
+++ b/services/core/java/com/android/server/DeviceIdleInternal.java
@@ -0,0 +1,52 @@
+/*
+ * 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;
+
+import com.android.server.deviceidle.IDeviceIdleConstraint;
+
+public interface DeviceIdleInternal {
+ void onConstraintStateChanged(IDeviceIdleConstraint constraint, boolean active);
+
+ void registerDeviceIdleConstraint(IDeviceIdleConstraint constraint, String name,
+ @IDeviceIdleConstraint.MinimumState int minState);
+
+ void unregisterDeviceIdleConstraint(IDeviceIdleConstraint constraint);
+
+ void exitIdle(String reason);
+
+ // duration in milliseconds
+ void addPowerSaveTempWhitelistApp(int callingUid, String packageName,
+ long duration, int userId, boolean sync, String reason);
+
+ // duration in milliseconds
+ void addPowerSaveTempWhitelistAppDirect(int uid, long duration, boolean sync,
+ String reason);
+
+ // duration in milliseconds
+ long getNotificationWhitelistDuration();
+
+ void setJobsActive(boolean active);
+
+ // Up-call from alarm manager.
+ void setAlarmsActive(boolean active);
+
+ boolean isAppOnWhitelist(int appid);
+
+ int[] getPowerSaveWhitelistUserAppIds();
+
+ int[] getPowerSaveTempWhitelistAppIds();
+}
diff --git a/services/core/java/com/android/server/DisplayThread.java b/services/core/java/com/android/server/DisplayThread.java
index 85c799c..a07ade0 100644
--- a/services/core/java/com/android/server/DisplayThread.java
+++ b/services/core/java/com/android/server/DisplayThread.java
@@ -20,6 +20,8 @@
import android.os.Process;
import android.os.Trace;
+import com.android.internal.annotations.VisibleForTesting;
+
/**
* Shared singleton foreground thread for the system. This is a thread for
* operations that affect what's on the display, which needs to have a minimum
@@ -58,4 +60,20 @@
return sHandler;
}
}
+
+ /**
+ * Disposes current display thread if it's initialized. Should only be used in tests to set up a
+ * new environment.
+ */
+ @VisibleForTesting
+ public static void dispose() {
+ synchronized (DisplayThread.class) {
+ if (sInstance == null) {
+ return;
+ }
+
+ getHandler().runWithScissors(() -> sInstance.quit(), 0 /* timeout */);
+ sInstance = null;
+ }
+ }
}
diff --git a/services/core/java/com/android/server/GraphicsStatsService.java b/services/core/java/com/android/server/GraphicsStatsService.java
index 4639d75..70569db 100644
--- a/services/core/java/com/android/server/GraphicsStatsService.java
+++ b/services/core/java/com/android/server/GraphicsStatsService.java
@@ -191,7 +191,7 @@
if (!file.getFileDescriptor().valid()) {
throw new IllegalStateException("Invalid file descriptor");
}
- return new ParcelFileDescriptor(file.getFileDescriptor());
+ return ParcelFileDescriptor.dup(file.getFileDescriptor());
} catch (IOException ex) {
throw new IllegalStateException("Failed to get PFD from memory file", ex);
}
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
index dee89e5..ea3dd3d 100644
--- a/services/core/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -25,7 +25,7 @@
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.VersionedPackage;
-import android.net.NetworkStackClient;
+import android.net.ConnectivityModuleConnector;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
@@ -116,7 +116,7 @@
// File containing the XML data of monitored packages /data/system/package-watchdog.xml
private final AtomicFile mPolicyFile;
private final ExplicitHealthCheckController mHealthCheckController;
- private final NetworkStackClient mNetworkStackClient;
+ private final ConnectivityModuleConnector mConnectivityModuleConnector;
@GuardedBy("mLock")
private boolean mIsPackagesReady;
// Flag to control whether explicit health checks are supported or not
@@ -138,7 +138,7 @@
"package-watchdog.xml")),
new Handler(Looper.myLooper()), BackgroundThread.getHandler(),
new ExplicitHealthCheckController(context),
- NetworkStackClient.getInstance());
+ ConnectivityModuleConnector.getInstance());
}
/**
@@ -147,13 +147,13 @@
@VisibleForTesting
PackageWatchdog(Context context, AtomicFile policyFile, Handler shortTaskHandler,
Handler longTaskHandler, ExplicitHealthCheckController controller,
- NetworkStackClient networkStackClient) {
+ ConnectivityModuleConnector connectivityModuleConnector) {
mContext = context;
mPolicyFile = policyFile;
mShortTaskHandler = shortTaskHandler;
mLongTaskHandler = longTaskHandler;
mHealthCheckController = controller;
- mNetworkStackClient = networkStackClient;
+ mConnectivityModuleConnector = connectivityModuleConnector;
loadFromFile();
}
@@ -179,7 +179,7 @@
() -> syncRequestsAsync());
setPropertyChangedListenerLocked();
updateConfigs();
- registerNetworkStackHealthListener();
+ registerConnectivityModuleHealthListener();
}
}
@@ -743,11 +743,11 @@
}
}
- private void registerNetworkStackHealthListener() {
+ private void registerConnectivityModuleHealthListener() {
// TODO: have an internal method to trigger a rollback by reporting high severity errors,
// and rely on ActivityManager to inform the watchdog of severe network stack crashes
// instead of having this listener in parallel.
- mNetworkStackClient.registerHealthListener(
+ mConnectivityModuleConnector.registerHealthListener(
packageName -> {
final VersionedPackage pkg = getVersionedPackage(packageName);
if (pkg == null) {
diff --git a/services/core/java/com/android/server/SystemService.java b/services/core/java/com/android/server/SystemService.java
index 8e9e74e..4facf4ea 100644
--- a/services/core/java/com/android/server/SystemService.java
+++ b/services/core/java/com/android/server/SystemService.java
@@ -18,12 +18,17 @@
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_DEFAULT;
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
import android.app.ActivityThread;
import android.content.Context;
+import android.content.pm.UserInfo;
import android.os.IBinder;
import android.os.ServiceManager;
import android.os.UserManager;
+import com.android.server.pm.UserManagerService;
+
/**
* The base class for services running in the system process. Override and implement
* the lifecycle event callback methods as needed.
@@ -145,11 +150,29 @@
public void onBootPhase(int phase) {}
/**
+ * @deprecated subclasses should extend {@link #onStartUser(int, int)} instead (which by default
+ * calls this method).
+ */
+ @Deprecated
+ public void onStartUser(@UserIdInt int userHandle) {}
+
+ /**
* Called when a new user is starting, for system services to initialize any per-user
* state they maintain for running users.
- * @param userHandle The identifier of the user.
+ *
+ * @param userInfo The information about the user. <b>NOTE: </b> this is a "live" object
+ * referenced by {@link UserManagerService} and hence should not be modified.
*/
- public void onStartUser(int userHandle) {}
+ public void onStartUser(@NonNull UserInfo userInfo) {
+ onStartUser(userInfo.id);
+ }
+
+ /**
+ * @deprecated subclasses should extend {@link #onUnlockUser(int, int)} instead (which by
+ * default calls this method).
+ */
+ @Deprecated
+ public void onUnlockUser(@UserIdInt int userHandle) {}
/**
* Called when an existing user is in the process of being unlocked. This
@@ -163,17 +186,38 @@
* {@link UserManager#isUserUnlockingOrUnlocked(int)} to handle both of
* these states.
*
- * @param userHandle The identifier of the user.
+ * @param userInfo The information about the user. <b>NOTE: </b> this is a "live" object
+ * referenced by {@link UserManagerService} and hence should not be modified.
*/
- public void onUnlockUser(int userHandle) {}
+ public void onUnlockUser(@NonNull UserInfo userInfo) {
+ onUnlockUser(userInfo.id);
+ }
+
+ /**
+ * @deprecated subclasses should extend {@link #onSwitchUser(int, int)} instead (which by
+ * default calls this method).
+ */
+ @Deprecated
+ public void onSwitchUser(@UserIdInt int userHandle) {}
/**
* Called when switching to a different foreground user, for system services that have
* special behavior for whichever user is currently in the foreground. This is called
* before any application processes are aware of the new user.
- * @param userHandle The identifier of the user.
+ *
+ * @param userInfo The information about the user. <b>NOTE: </b> this is a "live" object
+ * referenced by {@link UserManagerService} and hence should not be modified.
*/
- public void onSwitchUser(int userHandle) {}
+ public void onSwitchUser(@NonNull UserInfo userInfo) {
+ onSwitchUser(userInfo.id);
+ }
+
+ /**
+ * @deprecated subclasses should extend {@link #onStopUser(int, int)} instead (which by default
+ * calls this method).
+ */
+ @Deprecated
+ public void onStopUser(@UserIdInt int userHandle) {}
/**
* Called when an existing user is stopping, for system services to finalize any per-user
@@ -183,9 +227,19 @@
*
* <p>NOTE: This is the last callback where the callee may access the target user's CE storage.
*
- * @param userHandle The identifier of the user.
+ * @param userInfo The information about the user. <b>NOTE: </b> this is a "live" object
+ * referenced by {@link UserManagerService} and hence should not be modified.
*/
- public void onStopUser(int userHandle) {}
+ public void onStopUser(@NonNull UserInfo userInfo) {
+ onStopUser(userInfo.id);
+ }
+
+ /**
+ * @deprecated subclasses should extend {@link #onCleanupUser(int, int)} instead (which by
+ * default calls this method).
+ */
+ @Deprecated
+ public void onCleanupUser(@UserIdInt int userHandle) {}
/**
* Called when an existing user is stopping, for system services to finalize any per-user
@@ -193,11 +247,14 @@
* teardown of the user is complete.
*
* <p>NOTE: When this callback is called, the CE storage for the target user may not be
- * accessible already. Use {@link #onStopUser} instead if you need to access the CE storage.
+ * accessible already. Use {@link #onCleanupUser} instead if you need to access the CE storage.
*
- * @param userHandle The identifier of the user.
+ * @param userInfo The information about the user. <b>NOTE: </b> this is a "live" object
+ * referenced by {@link UserManagerService} and hence should not be modified.
*/
- public void onCleanupUser(int userHandle) {}
+ public void onCleanupUser(@NonNull UserInfo userInfo) {
+ onCleanupUser(userInfo.id);
+ }
/**
* Publish the service so it is accessible to other services and apps.
diff --git a/services/core/java/com/android/server/SystemServiceManager.java b/services/core/java/com/android/server/SystemServiceManager.java
index 9711152..ebe23f6 100644
--- a/services/core/java/com/android/server/SystemServiceManager.java
+++ b/services/core/java/com/android/server/SystemServiceManager.java
@@ -19,9 +19,11 @@
import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.content.Context;
+import android.content.pm.UserInfo;
import android.os.Environment;
import android.os.SystemClock;
import android.os.Trace;
+import android.os.UserManagerInternal;
import android.util.Slog;
import com.android.server.utils.TimingsTraceAndSlog;
@@ -53,6 +55,8 @@
private int mCurrentPhase = -1;
+ private UserManagerInternal mUserManagerInternal;
+
SystemServiceManager(Context context) {
mContext = context;
}
@@ -187,11 +191,30 @@
}
/**
+ * Called at the beginning of {@code ActivityManagerService.systemReady()}.
+ */
+ public void preSystemReady() {
+ mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
+ }
+
+ private @NonNull UserInfo getUserInfo(@UserIdInt int userHandle) {
+ if (mUserManagerInternal == null) {
+ throw new IllegalStateException("mUserManagerInternal not set yet");
+ }
+ final UserInfo userInfo = mUserManagerInternal.getUserInfo(userHandle);
+ if (userInfo == null) {
+ throw new IllegalStateException("No UserInfo for " + userHandle);
+ }
+ return userInfo;
+ }
+
+ /**
* Starts the given user.
*/
- public void startUser(@NonNull TimingsTraceAndSlog t, final @UserIdInt int userHandle) {
+ public void startUser(final @NonNull TimingsTraceAndSlog t, final @UserIdInt int userHandle) {
t.traceBegin("ssm.startUser-" + userHandle);
Slog.i(TAG, "Calling onStartUser u" + userHandle);
+ final UserInfo userInfo = getUserInfo(userHandle);
final int serviceLen = mServices.size();
for (int i = 0; i < serviceLen; i++) {
final SystemService service = mServices.get(i);
@@ -199,7 +222,7 @@
t.traceBegin("onStartUser-" + userHandle + " " + serviceName);
long time = SystemClock.elapsedRealtime();
try {
- service.onStartUser(userHandle);
+ service.onStartUser(userInfo);
} catch (Exception ex) {
Slog.wtf(TAG, "Failure reporting start of user " + userHandle
+ " to service " + service.getClass().getName(), ex);
@@ -217,6 +240,7 @@
final TimingsTraceAndSlog t = TimingsTraceAndSlog.newAsyncLog();
t.traceBegin("ssm.unlockUser-" + userHandle);
Slog.i(TAG, "Calling onUnlockUser u" + userHandle);
+ final UserInfo userInfo = getUserInfo(userHandle);
final int serviceLen = mServices.size();
for (int i = 0; i < serviceLen; i++) {
final SystemService service = mServices.get(i);
@@ -224,7 +248,7 @@
t.traceBegin("onUnlockUser-" + userHandle + " " + serviceName);
long time = SystemClock.elapsedRealtime();
try {
- service.onUnlockUser(userHandle);
+ service.onUnlockUser(userInfo);
} catch (Exception ex) {
Slog.wtf(TAG, "Failure reporting unlock of user " + userHandle
+ " to service " + serviceName, ex);
@@ -242,6 +266,7 @@
final TimingsTraceAndSlog t = TimingsTraceAndSlog.newAsyncLog();
t.traceBegin("ssm.switchUser-" + userHandle);
Slog.i(TAG, "Calling switchUser u" + userHandle);
+ final UserInfo userInfo = getUserInfo(userHandle);
final int serviceLen = mServices.size();
for (int i = 0; i < serviceLen; i++) {
final SystemService service = mServices.get(i);
@@ -249,7 +274,7 @@
t.traceBegin("onSwitchUser-" + userHandle + " " + serviceName);
long time = SystemClock.elapsedRealtime();
try {
- service.onSwitchUser(userHandle);
+ service.onSwitchUser(userInfo);
} catch (Exception ex) {
Slog.wtf(TAG, "Failure reporting switch of user " + userHandle
+ " to service " + serviceName, ex);
@@ -267,6 +292,7 @@
final TimingsTraceAndSlog t = TimingsTraceAndSlog.newAsyncLog();
t.traceBegin("ssm.stopUser-" + userHandle);
Slog.i(TAG, "Calling onStopUser u" + userHandle);
+ final UserInfo userInfo = getUserInfo(userHandle);
final int serviceLen = mServices.size();
for (int i = 0; i < serviceLen; i++) {
final SystemService service = mServices.get(i);
@@ -274,7 +300,7 @@
t.traceBegin("onStopUser-" + userHandle + " " + serviceName);
long time = SystemClock.elapsedRealtime();
try {
- service.onStopUser(userHandle);
+ service.onStopUser(userInfo);
} catch (Exception ex) {
Slog.wtf(TAG, "Failure reporting stop of user " + userHandle
+ " to service " + serviceName, ex);
@@ -292,6 +318,7 @@
final TimingsTraceAndSlog t = TimingsTraceAndSlog.newAsyncLog();
t.traceBegin("ssm.cleanupUser-" + userHandle);
Slog.i(TAG, "Calling onCleanupUser u" + userHandle);
+ final UserInfo userInfo = getUserInfo(userHandle);
final int serviceLen = mServices.size();
for (int i = 0; i < serviceLen; i++) {
final SystemService service = mServices.get(i);
@@ -299,7 +326,7 @@
t.traceBegin("onCleanupUser-" + userHandle + " " + serviceName);
long time = SystemClock.elapsedRealtime();
try {
- service.onCleanupUser(userHandle);
+ service.onCleanupUser(userInfo);
} catch (Exception ex) {
Slog.wtf(TAG, "Failure reporting cleanup of user " + userHandle
+ " to service " + serviceName, ex);
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index e66e596..f7e825e 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -1027,7 +1027,12 @@
log(str);
}
mLocalLog.log(str);
- if (validatePhoneId(phoneId)) {
+ // for service state updates, don't notify clients when subId is invalid. This prevents
+ // us from sending incorrect notifications like b/133140128
+ // In the future, we can remove this logic for every notification here and add a
+ // callback so listeners know when their PhoneStateListener's subId becomes invalid, but
+ // for now we use the simplest fix.
+ if (validatePhoneId(phoneId) && SubscriptionManager.isValidSubscriptionId(subId)) {
mServiceState[phoneId] = state;
for (Record r : mRecords) {
@@ -1059,7 +1064,8 @@
}
}
} else {
- log("notifyServiceStateForSubscriber: INVALID phoneId=" + phoneId);
+ log("notifyServiceStateForSubscriber: INVALID phoneId=" + phoneId
+ + " or subId=" + subId);
}
handleRemoveListLocked();
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ede573a..2292889 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -282,6 +282,7 @@
import android.util.ArraySet;
import android.util.DebugUtils;
import android.util.EventLog;
+import android.util.FeatureFlagUtils;
import android.util.Log;
import android.util.Pair;
import android.util.PrintWriterPrinter;
@@ -330,7 +331,7 @@
import com.android.internal.util.function.TriFunction;
import com.android.server.AlarmManagerInternal;
import com.android.server.AttributeCache;
-import com.android.server.DeviceIdleController;
+import com.android.server.DeviceIdleInternal;
import com.android.server.DisplayThread;
import com.android.server.IntentResolver;
import com.android.server.IoThread;
@@ -378,7 +379,7 @@
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringWriter;
-import java.io.UnsupportedEncodingException;
+import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
@@ -437,6 +438,10 @@
// need not be the case.
public static final String ACTION_TRIGGER_IDLE = "com.android.server.ACTION_TRIGGER_IDLE";
+ private static final String INTENT_BUGREPORT_REQUESTED =
+ "com.android.internal.intent.action.BUGREPORT_REQUESTED";
+ private static final String SHELL_APP_PACKAGE = "com.android.shell";
+
/** Control over CPU and battery monitoring */
// write battery stats every 30 minutes.
static final long BATTERY_STATS_TIME = 30 * 60 * 1000;
@@ -555,6 +560,10 @@
OomAdjuster mOomAdjuster;
final LowMemDetector mLowMemDetector;
+ static final String EXTRA_TITLE = "android.intent.extra.TITLE";
+ static final String EXTRA_DESCRIPTION = "android.intent.extra.DESCRIPTION";
+ static final String EXTRA_BUGREPORT_TYPE = "android.intent.extra.BUGREPORT_TYPE";
+
/** All system services */
SystemServiceManager mSystemServiceManager;
@@ -1135,7 +1144,7 @@
/**
* Access to DeviceIdleController service.
*/
- DeviceIdleController.LocalService mLocalDeviceIdleController;
+ DeviceIdleInternal mLocalDeviceIdleController;
/**
* Power-save whitelisted app-ids (not including except-idle-whitelisted ones).
@@ -1480,8 +1489,9 @@
public ActivityTaskManagerService mActivityTaskManager;
@VisibleForTesting
public ActivityTaskManagerInternal mAtmInternal;
+ UriGrantsManagerInternal mUgmInternal;
@VisibleForTesting
- public UriGrantsManagerInternal mUgmInternal;
+ public final ActivityManagerInternal mInternal;
final ActivityThread mSystemThread;
private final class AppDeathRecipient implements IBinder.DeathRecipient {
@@ -2413,6 +2423,8 @@
mProcStartHandler = null;
mHiddenApiBlacklist = null;
mFactoryTest = FACTORY_TEST_OFF;
+ mUgmInternal = LocalServices.getService(UriGrantsManagerInternal.class);
+ mInternal = new LocalService();
}
// Note: This method is invoked on the main thread but may need to attach various
@@ -2566,6 +2578,7 @@
Slog.w(TAG, "Setting background thread cpuset failed");
}
+ mInternal = new LocalService();
}
public void setSystemServiceManager(SystemServiceManager mgr) {
@@ -2583,7 +2596,7 @@
mBatteryStatsService.publish();
mAppOpsService.publish(mContext);
Slog.d("AppOps", "AppOpsService published");
- LocalServices.addService(ActivityManagerInternal.class, new LocalService());
+ LocalServices.addService(ActivityManagerInternal.class, mInternal);
mActivityTaskManager.onActivityManagerInternalAdded();
mUgmInternal.onActivityManagerInternalAdded();
mPendingIntentController.onActivityManagerInternalAdded();
@@ -8197,6 +8210,53 @@
@Deprecated
@Override
public void requestBugReport(int bugreportType) {
+ requestBugReportWithDescription(null, null, bugreportType);
+ }
+
+ /**
+ * @deprecated This method is only used by a few internal components and it will soon be
+ * replaced by a proper bug report API (which will be restricted to a few, pre-defined apps).
+ * No new code should be calling it.
+ */
+ @Deprecated
+ public void requestBugReportWithDescription(@Nullable String shareTitle,
+ @Nullable String shareDescription, int bugreportType) {
+ if (!TextUtils.isEmpty(shareTitle)) {
+ if (shareTitle.length() > MAX_BUGREPORT_TITLE_SIZE) {
+ String errorStr = "shareTitle should be less than " +
+ MAX_BUGREPORT_TITLE_SIZE + " characters";
+ throw new IllegalArgumentException(errorStr);
+ }
+ if (!TextUtils.isEmpty(shareDescription)) {
+ int length = shareDescription.getBytes(StandardCharsets.UTF_8).length;
+ if (length > SystemProperties.PROP_VALUE_MAX) {
+ String errorStr = "shareTitle should be less than " +
+ SystemProperties.PROP_VALUE_MAX + " bytes";
+ throw new IllegalArgumentException(errorStr);
+ } else {
+ SystemProperties.set("dumpstate.options.description", shareDescription);
+ }
+ }
+ SystemProperties.set("dumpstate.options.title", shareTitle);
+ Slog.d(TAG, "Bugreport notification title " + shareTitle
+ + " description " + shareDescription);
+ }
+ final boolean useApi = FeatureFlagUtils.isEnabled(mContext,
+ FeatureFlagUtils.USE_BUGREPORT_API);
+
+ if (useApi) {
+ // Create intent to trigger Bugreport API via Shell
+ Intent triggerShellBugreport = new Intent();
+ triggerShellBugreport.setAction(INTENT_BUGREPORT_REQUESTED);
+ triggerShellBugreport.setPackage(SHELL_APP_PACKAGE);
+ triggerShellBugreport.putExtra(EXTRA_BUGREPORT_TYPE, bugreportType);
+ if (shareTitle != null) {
+ triggerShellBugreport.putExtra(EXTRA_TITLE, shareTitle);
+ }
+ if (shareDescription != null) {
+ triggerShellBugreport.putExtra(EXTRA_DESCRIPTION, shareDescription);
+ }
+ }
String extraOptions = null;
switch (bugreportType) {
case ActivityManager.BUGREPORT_OPTION_FULL:
@@ -8238,45 +8298,6 @@
* No new code should be calling it.
*/
@Deprecated
- private void requestBugReportWithDescription(String shareTitle, String shareDescription,
- int bugreportType) {
- if (!TextUtils.isEmpty(shareTitle)) {
- if (shareTitle.length() > MAX_BUGREPORT_TITLE_SIZE) {
- String errorStr = "shareTitle should be less than " +
- MAX_BUGREPORT_TITLE_SIZE + " characters";
- throw new IllegalArgumentException(errorStr);
- } else {
- if (!TextUtils.isEmpty(shareDescription)) {
- int length;
- try {
- length = shareDescription.getBytes("UTF-8").length;
- } catch (UnsupportedEncodingException e) {
- String errorStr = "shareDescription: UnsupportedEncodingException";
- throw new IllegalArgumentException(errorStr);
- }
- if (length > SystemProperties.PROP_VALUE_MAX) {
- String errorStr = "shareTitle should be less than " +
- SystemProperties.PROP_VALUE_MAX + " bytes";
- throw new IllegalArgumentException(errorStr);
- } else {
- SystemProperties.set("dumpstate.options.description", shareDescription);
- }
- }
- SystemProperties.set("dumpstate.options.title", shareTitle);
- }
- }
-
- Slog.d(TAG, "Bugreport notification title " + shareTitle
- + " description " + shareDescription);
- requestBugReport(bugreportType);
- }
-
- /**
- * @deprecated This method is only used by a few internal components and it will soon be
- * replaced by a proper bug report API (which will be restricted to a few, pre-defined apps).
- * No new code should be calling it.
- */
- @Deprecated
@Override
public void requestTelephonyBugReport(String shareTitle, String shareDescription) {
requestBugReportWithDescription(shareTitle, shareDescription,
@@ -8990,6 +9011,7 @@
*/
public void systemReady(final Runnable goingCallback, @NonNull TimingsTraceAndSlog t) {
t.traceBegin("PhaseActivityManagerReady");
+ mSystemServiceManager.preSystemReady();
synchronized(this) {
if (mSystemReady) {
// If we're done calling all the receivers, run the next "boot phase" passed in
@@ -9002,8 +9024,8 @@
}
t.traceBegin("controllersReady");
- mLocalDeviceIdleController
- = LocalServices.getService(DeviceIdleController.LocalService.class);
+ mLocalDeviceIdleController =
+ LocalServices.getService(DeviceIdleInternal.class);
mActivityTaskManager.onSystemReady();
// Make sure we have the current profile info, since it is needed for security checks.
mUserController.onSystemReady();
@@ -9139,8 +9161,12 @@
mAtmInternal.showSystemReadyErrorDialogsIfNeeded();
t.traceEnd();
- boolean isSystemUser = currentUserId == UserHandle.USER_SYSTEM;
- if (isSystemUser) {
+ // Some systems - like automotive - will explicitly unlock system user then switch
+ // to a secondary user. Hence, we don't want to send duplicate broadcasts for the
+ // system user here.
+ boolean sendSystemUserBroadcasts = currentUserId == UserHandle.USER_SYSTEM;
+
+ if (sendSystemUserBroadcasts) {
t.traceBegin("sendUserStartBroadcast");
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
@@ -9181,7 +9207,7 @@
mAtmInternal.resumeTopActivities(false /* scheduleIdle */);
t.traceEnd();
- if (isSystemUser) {
+ if (sendSystemUserBroadcasts) {
t.traceBegin("sendUserSwitchBroadcasts");
mUserController.sendUserSwitchBroadcasts(-1, currentUserId);
t.traceEnd();
diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java
index 9cf342c..ace0a7d 100644
--- a/services/core/java/com/android/server/appop/HistoricalRegistry.java
+++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java
@@ -291,7 +291,7 @@
makeRelativeToEpochStart(currentOps, nowMillis);
currentOps.accept(visitor);
- if(isPersistenceInitializedMLocked()) {
+ if (!isPersistenceInitializedMLocked()) {
Slog.e(LOG_TAG, "Interaction before persistence initialized");
return;
}
@@ -457,7 +457,7 @@
// it is a part of the persistence initialization process.
boolean resampleHistory = false;
Slog.i(LOG_TAG, "New history parameters: mode:"
- + AppOpsManager.historicalModeToString(mMode) + " baseSnapshotInterval:"
+ + AppOpsManager.historicalModeToString(mode) + " baseSnapshotInterval:"
+ baseSnapshotInterval + " intervalCompressionMultiplier:"
+ intervalCompressionMultiplier);
if (mMode != mode) {
@@ -1066,7 +1066,7 @@
normalizeSnapshotForSlotDuration(persistedOps, slotDurationMillis);
writeHistoricalOpsDLocked(persistedOps, intervalOverflowMillis, newFile);
if (DEBUG) {
- Slog.i(LOG_TAG, "Persisted at depth: " + depth
+ Slog.i(LOG_TAG, "Persisted at depth: " + depth + " file: " + newFile
+ " ops:\n" + opsToDebugString(persistedOps));
enforceOpsWellFormed(persistedOps);
}
@@ -1160,7 +1160,7 @@
}
if (DEBUG) {
if (allOps != null) {
- Slog.i(LOG_TAG, "Read from file: " + file + "ops:\n"
+ Slog.i(LOG_TAG, "Read from file: " + file + " ops:\n"
+ opsToDebugString(allOps));
enforceOpsWellFormed(allOps);
}
diff --git a/services/core/java/com/android/server/biometrics/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/AuthenticationClient.java
index 4a9ccde..766e5c4 100644
--- a/services/core/java/com/android/server/biometrics/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/AuthenticationClient.java
@@ -209,8 +209,7 @@
// will show briefly and be replaced by "device locked out" message.
if (listener != null) {
if (isBiometricPrompt()) {
- listener.onAuthenticationFailedInternal(getCookie(),
- getRequireConfirmation());
+ listener.onAuthenticationFailedInternal();
} else {
listener.onAuthenticationFailed(getHalDeviceId());
}
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index af2f24f..24e6a75 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -25,11 +25,9 @@
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_NONE;
import android.app.ActivityManager;
-import android.app.ActivityTaskManager;
import android.app.AppOpsManager;
-import android.app.IActivityTaskManager;
+import android.app.IActivityManager;
import android.app.KeyguardManager;
-import android.app.TaskStackListener;
import android.app.UserSwitchObserver;
import android.content.ContentResolver;
import android.content.Context;
@@ -69,6 +67,7 @@
import android.util.StatsLog;
import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.SomeArgs;
import com.android.internal.statusbar.IStatusBarService;
import com.android.server.SystemService;
@@ -88,9 +87,8 @@
private static final String TAG = "BiometricService";
private static final boolean DEBUG = true;
- private static final int MSG_ON_TASK_STACK_CHANGED = 1;
private static final int MSG_ON_AUTHENTICATION_SUCCEEDED = 2;
- private static final int MSG_ON_AUTHENTICATION_FAILED = 3;
+ private static final int MSG_ON_AUTHENTICATION_REJECTED = 3;
private static final int MSG_ON_ERROR = 4;
private static final int MSG_ON_ACQUIRED = 5;
private static final int MSG_ON_DISMISSED = 6;
@@ -101,6 +99,7 @@
private static final int MSG_ON_CONFIRM_DEVICE_CREDENTIAL_SUCCESS = 11;
private static final int MSG_ON_CONFIRM_DEVICE_CREDENTIAL_ERROR = 12;
private static final int MSG_REGISTER_CANCELLATION_CALLBACK = 13;
+ private static final int MSG_ON_AUTHENTICATION_TIMED_OUT = 14;
private static final int[] FEATURE_ID = {
TYPE_FINGERPRINT,
@@ -112,33 +111,41 @@
* Authentication either just called and we have not transitioned to the CALLED state, or
* authentication terminated (success or error).
*/
- private static final int STATE_AUTH_IDLE = 0;
+ static final int STATE_AUTH_IDLE = 0;
/**
* Authentication was called and we are waiting for the <Biometric>Services to return their
* cookies before starting the hardware and showing the BiometricPrompt.
*/
- private static final int STATE_AUTH_CALLED = 1;
+ static final int STATE_AUTH_CALLED = 1;
/**
* Authentication started, BiometricPrompt is showing and the hardware is authenticating.
*/
- private static final int STATE_AUTH_STARTED = 2;
+ static final int STATE_AUTH_STARTED = 2;
/**
* Authentication is paused, waiting for the user to press "try again" button. Only
* passive modalities such as Face or Iris should have this state. Note that for passive
* modalities, the HAL enters the idle state after onAuthenticated(false) which differs from
* fingerprint.
*/
- private static final int STATE_AUTH_PAUSED = 3;
+ static final int STATE_AUTH_PAUSED = 3;
/**
* Authentication is successful, but we're waiting for the user to press "confirm" button.
*/
- private static final int STATE_AUTH_PENDING_CONFIRM = 5;
+ static final int STATE_AUTH_PENDING_CONFIRM = 5;
/**
* Biometric authentication was canceled, but the device is now showing ConfirmDeviceCredential
*/
- private static final int STATE_BIOMETRIC_AUTH_CANCELED_SHOWING_CDC = 6;
+ static final int STATE_BIOMETRIC_AUTH_CANCELED_SHOWING_CDC = 6;
+ /**
+ * Biometric authenticated, waiting for SysUI to finish animation
+ */
+ static final int STATE_AUTHENTICATED_PENDING_SYSUI = 7;
+ /**
+ * Biometric error, waiting for SysUI to finish animation
+ */
+ static final int STATE_ERROR_PENDING_SYSUI = 8;
- private final class AuthSession implements IBinder.DeathRecipient {
+ final class AuthSession implements IBinder.DeathRecipient {
// Map of Authenticator/Cookie pairs. We expect to receive the cookies back from
// <Biometric>Services before we can start authenticating. Pairs that have been returned
// are moved to mModalitiesMatched.
@@ -165,10 +172,13 @@
final boolean mRequireConfirmation;
// The current state, which can be either idle, called, or started
- private int mState = STATE_AUTH_IDLE;
+ int mState = STATE_AUTH_IDLE;
// For explicit confirmation, do not send to keystore until the user has confirmed
// the authentication.
byte[] mTokenEscrow;
+ // Waiting for SystemUI to complete animation
+ int mErrorEscrow;
+ String mErrorStringEscrow;
// Timestamp when authentication started
private long mStartTimeMs;
@@ -244,42 +254,37 @@
}
}
- private final class BiometricTaskStackListener extends TaskStackListener {
- @Override
- public void onTaskStackChanged() {
- mHandler.sendEmptyMessage(MSG_ON_TASK_STACK_CHANGED);
- }
- }
-
+ private final Injector mInjector;
+ @VisibleForTesting
+ final IBiometricService.Stub mImpl;
private final AppOpsManager mAppOps;
private final boolean mHasFeatureFingerprint;
private final boolean mHasFeatureIris;
private final boolean mHasFeatureFace;
- private final SettingObserver mSettingObserver;
+ @VisibleForTesting
+ SettingObserver mSettingObserver;
private final List<EnabledOnKeyguardCallback> mEnabledOnKeyguardCallbacks;
- private final BiometricTaskStackListener mTaskStackListener = new BiometricTaskStackListener();
private final Random mRandom = new Random();
- private IFingerprintService mFingerprintService;
- private IFaceService mFaceService;
- private IActivityTaskManager mActivityTaskManager;
- private IStatusBarService mStatusBarService;
+ @VisibleForTesting
+ IFingerprintService mFingerprintService;
+ @VisibleForTesting
+ IFaceService mFaceService;
+ @VisibleForTesting
+ IStatusBarService mStatusBarService;
+ @VisibleForTesting
+ KeyStore mKeyStore;
// Get and cache the available authenticator (manager) classes. Used since aidl doesn't support
// polymorphism :/
final ArrayList<Authenticator> mAuthenticators = new ArrayList<>();
- // Cache the current service that's being used. This is the service which
- // cancelAuthentication() must be forwarded to. This is just a cache, and the actual
- // check (is caller the current client) is done in the <Biometric>Service.
- // Since Settings/System (not application) is responsible for changing preference, this
- // should be safe.
- private int mCurrentModality;
-
// The current authentication session, null if idle/done. We need to track both the current
// and pending sessions since errors may be sent to either.
- private AuthSession mCurrentAuthSession;
- private AuthSession mPendingAuthSession;
+ @VisibleForTesting
+ AuthSession mCurrentAuthSession;
+ @VisibleForTesting
+ AuthSession mPendingAuthSession;
// TODO(b/123378871): Remove when moved.
// When BiometricPrompt#setAllowDeviceCredentials is set to true, we need to store the
@@ -289,15 +294,11 @@
// to this receiver.
private IBiometricServiceReceiver mConfirmDeviceCredentialReceiver;
- private final Handler mHandler = new Handler(Looper.getMainLooper()) {
+ @VisibleForTesting
+ final Handler mHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
- case MSG_ON_TASK_STACK_CHANGED: {
- handleTaskStackChanged();
- break;
- }
-
case MSG_ON_AUTHENTICATION_SUCCEEDED: {
SomeArgs args = (SomeArgs) msg.obj;
handleAuthenticationSucceeded(
@@ -307,8 +308,8 @@
break;
}
- case MSG_ON_AUTHENTICATION_FAILED: {
- handleAuthenticationFailed((String) msg.obj /* failureReason */);
+ case MSG_ON_AUTHENTICATION_REJECTED: {
+ handleAuthenticationRejected((String) msg.obj /* failureReason */);
break;
}
@@ -397,6 +398,11 @@
break;
}
+ case MSG_ON_AUTHENTICATION_TIMED_OUT: {
+ handleAuthenticationTimedOut((String) msg.obj /* errorMessage */);
+ break;
+ }
+
default:
Slog.e(TAG, "Unknown message: " + msg);
break;
@@ -422,7 +428,8 @@
}
}
- private final class SettingObserver extends ContentObserver {
+ @VisibleForTesting
+ public static class SettingObserver extends ContentObserver {
private static final boolean DEFAULT_KEYGUARD_ENABLED = true;
private static final boolean DEFAULT_APP_ENABLED = true;
@@ -436,6 +443,7 @@
Settings.Secure.getUriFor(Settings.Secure.FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION);
private final ContentResolver mContentResolver;
+ private final List<BiometricService.EnabledOnKeyguardCallback> mCallbacks;
private Map<Integer, Boolean> mFaceEnabledOnKeyguard = new HashMap<>();
private Map<Integer, Boolean> mFaceEnabledForApps = new HashMap<>();
@@ -446,13 +454,15 @@
*
* @param handler The handler to run {@link #onChange} on, or null if none.
*/
- SettingObserver(Handler handler) {
+ public SettingObserver(Context context, Handler handler,
+ List<BiometricService.EnabledOnKeyguardCallback> callbacks) {
super(handler);
- mContentResolver = getContext().getContentResolver();
+ mContentResolver = context.getContentResolver();
+ mCallbacks = callbacks;
updateContentObserver();
}
- void updateContentObserver() {
+ public void updateContentObserver() {
mContentResolver.unregisterContentObserver(this);
mContentResolver.registerContentObserver(FACE_UNLOCK_KEYGUARD_ENABLED,
false /* notifyForDescendents */,
@@ -495,7 +505,7 @@
}
}
- boolean getFaceEnabledOnKeyguard() {
+ public boolean getFaceEnabledOnKeyguard() {
final int user = ActivityManager.getCurrentUser();
if (!mFaceEnabledOnKeyguard.containsKey(user)) {
onChange(true /* selfChange */, FACE_UNLOCK_KEYGUARD_ENABLED, user);
@@ -503,22 +513,23 @@
return mFaceEnabledOnKeyguard.get(user);
}
- boolean getFaceEnabledForApps(int userId) {
+ public boolean getFaceEnabledForApps(int userId) {
+ Slog.e(TAG, "getFaceEnabledForApps: " + userId, new Exception());
if (!mFaceEnabledForApps.containsKey(userId)) {
onChange(true /* selfChange */, FACE_UNLOCK_APP_ENABLED, userId);
}
return mFaceEnabledForApps.getOrDefault(userId, DEFAULT_APP_ENABLED);
}
- boolean getFaceAlwaysRequireConfirmation(int userId) {
+ public boolean getFaceAlwaysRequireConfirmation(int userId) {
if (!mFaceAlwaysRequireConfirmation.containsKey(userId)) {
onChange(true /* selfChange */, FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION, userId);
}
return mFaceAlwaysRequireConfirmation.get(userId);
}
- void notifyEnabledOnKeyguardCallbacks(int userId) {
- List<EnabledOnKeyguardCallback> callbacks = mEnabledOnKeyguardCallbacks;
+ public void notifyEnabledOnKeyguardCallbacks(int userId) {
+ List<EnabledOnKeyguardCallback> callbacks = mCallbacks;
for (int i = 0; i < callbacks.size(); i++) {
callbacks.get(i).notify(BiometricSourceType.FACE,
mFaceEnabledOnKeyguard.getOrDefault(userId, DEFAULT_KEYGUARD_ENABLED),
@@ -527,7 +538,7 @@
}
}
- private final class EnabledOnKeyguardCallback implements IBinder.DeathRecipient {
+ final class EnabledOnKeyguardCallback implements IBinder.DeathRecipient {
private final IBiometricEnabledOnKeyguardCallback mCallback;
@@ -559,7 +570,8 @@
}
// Wrap the client's receiver so we can do things with the BiometricDialog first
- private final IBiometricServiceReceiverInternal mInternalReceiver =
+ @VisibleForTesting
+ final IBiometricServiceReceiverInternal mInternalReceiver =
new IBiometricServiceReceiverInternal.Stub() {
@Override
public void onAuthenticationSucceeded(boolean requireConfirmation, byte[] token)
@@ -571,10 +583,11 @@
}
@Override
- public void onAuthenticationFailed(int cookie, boolean requireConfirmation)
+ public void onAuthenticationFailed()
throws RemoteException {
String failureReason = getContext().getString(R.string.biometric_not_recognized);
- mHandler.obtainMessage(MSG_ON_AUTHENTICATION_FAILED, failureReason).sendToTarget();
+ Slog.v(TAG, "onAuthenticationFailed: " + failureReason);
+ mHandler.obtainMessage(MSG_ON_AUTHENTICATION_REJECTED, failureReason).sendToTarget();
}
@Override
@@ -583,7 +596,7 @@
// soft errors and we should allow the user to try authenticating again instead of
// dismissing BiometricPrompt.
if (error == BiometricConstants.BIOMETRIC_ERROR_TIMEOUT) {
- mHandler.obtainMessage(MSG_ON_AUTHENTICATION_FAILED, message).sendToTarget();
+ mHandler.obtainMessage(MSG_ON_AUTHENTICATION_TIMED_OUT, message).sendToTarget();
} else {
SomeArgs args = SomeArgs.obtain();
args.argi1 = cookie;
@@ -873,6 +886,44 @@
}
}
+ @VisibleForTesting
+ static class Injector {
+ IActivityManager getActivityManagerService() {
+ return ActivityManager.getService();
+ }
+
+ IStatusBarService getStatusBarService() {
+ return IStatusBarService.Stub.asInterface(
+ ServiceManager.getService(Context.STATUS_BAR_SERVICE));
+ }
+
+ IFingerprintService getFingerprintService() {
+ return IFingerprintService.Stub.asInterface(
+ ServiceManager.getService(Context.FINGERPRINT_SERVICE));
+ }
+
+ IFaceService getFaceService() {
+ return IFaceService.Stub.asInterface(ServiceManager.getService(Context.FACE_SERVICE));
+ }
+
+ SettingObserver getSettingObserver(Context context, Handler handler,
+ List<EnabledOnKeyguardCallback> callbacks) {
+ return new SettingObserver(context, handler, callbacks);
+ }
+
+ KeyStore getKeyStore() {
+ return KeyStore.getInstance();
+ }
+
+ boolean isDebugEnabled(Context context, int userId) {
+ return Utils.isDebugEnabled(context, userId);
+ }
+
+ void publishBinderService(BiometricService service, IBiometricService.Stub impl) {
+ service.publishBinderService(Context.BIOMETRIC_SERVICE, impl);
+ }
+ }
+
/**
* Initializes the system service.
* <p>
@@ -883,11 +934,19 @@
* @param context The system server context.
*/
public BiometricService(Context context) {
+ this(context, new Injector());
+ }
+
+ @VisibleForTesting
+ BiometricService(Context context, Injector injector) {
super(context);
+ mInjector = injector;
+ mImpl = new BiometricServiceWrapper();
mAppOps = context.getSystemService(AppOpsManager.class);
mEnabledOnKeyguardCallbacks = new ArrayList<>();
- mSettingObserver = new SettingObserver(mHandler);
+ mSettingObserver = mInjector.getSettingObserver(context, mHandler,
+ mEnabledOnKeyguardCallbacks);
final PackageManager pm = context.getPackageManager();
mHasFeatureFingerprint = pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT);
@@ -895,7 +954,7 @@
mHasFeatureFace = pm.hasSystemFeature(PackageManager.FEATURE_FACE);
try {
- ActivityManager.getService().registerUserSwitchObserver(
+ injector.getActivityManagerService().registerUserSwitchObserver(
new UserSwitchObserver() {
@Override
public void onUserSwitchComplete(int newUserId) {
@@ -913,17 +972,14 @@
public void onStart() {
// TODO: maybe get these on-demand
if (mHasFeatureFingerprint) {
- mFingerprintService = IFingerprintService.Stub.asInterface(
- ServiceManager.getService(Context.FINGERPRINT_SERVICE));
+ mFingerprintService = mInjector.getFingerprintService();
}
if (mHasFeatureFace) {
- mFaceService = IFaceService.Stub.asInterface(
- ServiceManager.getService(Context.FACE_SERVICE));
+ mFaceService = mInjector.getFaceService();
}
- mActivityTaskManager = ActivityTaskManager.getService();
- mStatusBarService = IStatusBarService.Stub.asInterface(
- ServiceManager.getService(Context.STATUS_BAR_SERVICE));
+ mKeyStore = mInjector.getKeyStore();
+ mStatusBarService = mInjector.getStatusBarService();
// Cache the authenticators
for (int i = 0; i < FEATURE_ID.length; i++) {
@@ -934,7 +990,7 @@
}
}
- publishBinderService(Context.BIOMETRIC_SERVICE, new BiometricServiceWrapper());
+ mInjector.publishBinderService(this, mImpl);
}
/**
@@ -1068,7 +1124,7 @@
}
private void logDialogDismissed(int reason) {
- if (reason == BiometricPrompt.DISMISSED_REASON_POSITIVE) {
+ if (reason == BiometricPrompt.DISMISSED_REASON_CONFIRMED) {
// Explicit auth, authentication confirmed.
// Latency in this case is authenticated -> confirmed. <Biometric>Service
// should have the first half (first acquired -> authenticated).
@@ -1094,7 +1150,7 @@
mCurrentAuthSession.mRequireConfirmation,
StatsLog.BIOMETRIC_AUTHENTICATED__STATE__CONFIRMED,
latency,
- Utils.isDebugEnabled(getContext(), mCurrentAuthSession.mUserId));
+ mInjector.isDebugEnabled(getContext(), mCurrentAuthSession.mUserId));
} else {
final long latency = System.currentTimeMillis() - mCurrentAuthSession.mStartTimeMs;
@@ -1122,7 +1178,7 @@
BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT,
error,
0 /* vendorCode */,
- Utils.isDebugEnabled(getContext(), mCurrentAuthSession.mUserId),
+ mInjector.isDebugEnabled(getContext(), mCurrentAuthSession.mUserId),
latency);
}
}
@@ -1145,51 +1201,22 @@
return modality;
}
- private void handleTaskStackChanged() {
- try {
- final List<ActivityManager.RunningTaskInfo> runningTasks =
- mActivityTaskManager.getTasks(1);
- if (!runningTasks.isEmpty()) {
- final String topPackage = runningTasks.get(0).topActivity.getPackageName();
- if (mCurrentAuthSession != null
- && !topPackage.contentEquals(mCurrentAuthSession.mOpPackageName)) {
- mStatusBarService.hideBiometricDialog();
- mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
- mCurrentAuthSession.mClientReceiver.onError(
- BiometricConstants.BIOMETRIC_ERROR_CANCELED,
- getContext().getString(
- com.android.internal.R.string.biometric_error_canceled)
- );
- mCurrentAuthSession.mState = STATE_AUTH_IDLE;
- mCurrentAuthSession = null;
- }
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to get running tasks", e);
- }
- }
-
private void handleAuthenticationSucceeded(boolean requireConfirmation, byte[] token) {
-
try {
// Should never happen, log this to catch bad HAL behavior (e.g. auth succeeded
// after user dismissed/canceled dialog).
if (mCurrentAuthSession == null) {
- Slog.e(TAG, "onAuthenticationSucceeded(): Auth session is null");
+ Slog.e(TAG, "handleAuthenticationSucceeded: Auth session is null");
return;
}
+ // Store the auth token and submit it to keystore after the dialog is confirmed /
+ // animating away.
+ mCurrentAuthSession.mTokenEscrow = token;
if (!requireConfirmation) {
- mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
- KeyStore.getInstance().addAuthToken(token);
- mCurrentAuthSession.mClientReceiver.onAuthenticationSucceeded();
- mCurrentAuthSession.mState = STATE_AUTH_IDLE;
- mCurrentAuthSession = null;
+ mCurrentAuthSession.mState = STATE_AUTHENTICATED_PENDING_SYSUI;
} else {
mCurrentAuthSession.mAuthenticatedTimeMs = System.currentTimeMillis();
- // Store the auth token and submit it to keystore after the confirmation
- // button has been pressed.
- mCurrentAuthSession.mTokenEscrow = token;
mCurrentAuthSession.mState = STATE_AUTH_PENDING_CONFIRM;
}
@@ -1201,12 +1228,13 @@
}
}
- private void handleAuthenticationFailed(String failureReason) {
+ private void handleAuthenticationRejected(String failureReason) {
+ Slog.v(TAG, "handleAuthenticationRejected: " + failureReason);
try {
// Should never happen, log this to catch bad HAL behavior (e.g. auth succeeded
// after user dismissed/canceled dialog).
if (mCurrentAuthSession == null) {
- Slog.e(TAG, "onAuthenticationFailed(): Auth session is null");
+ Slog.e(TAG, "handleAuthenticationRejected: Auth session is null");
return;
}
@@ -1225,16 +1253,31 @@
}
}
+ private void handleAuthenticationTimedOut(String message) {
+ Slog.v(TAG, "handleAuthenticationTimedOut: " + message);
+ try {
+ // Should never happen, log this to catch bad HAL behavior (e.g. auth succeeded
+ // after user dismissed/canceled dialog).
+ if (mCurrentAuthSession == null) {
+ Slog.e(TAG, "handleAuthenticationTimedOut: Auth session is null");
+ return;
+ }
+
+ mStatusBarService.onBiometricAuthenticated(false, message);
+ mCurrentAuthSession.mState = STATE_AUTH_PAUSED;
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ }
+ }
+
private void handleOnConfirmDeviceCredentialSuccess() {
if (mConfirmDeviceCredentialReceiver == null) {
- Slog.w(TAG, "onCDCASuccess null!");
+ Slog.w(TAG, "handleOnConfirmDeviceCredentialSuccess null!");
return;
}
try {
- mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
mConfirmDeviceCredentialReceiver.onAuthenticationSucceeded();
if (mCurrentAuthSession != null) {
- mCurrentAuthSession.mState = STATE_AUTH_IDLE;
mCurrentAuthSession = null;
}
} catch (RemoteException e) {
@@ -1245,14 +1288,13 @@
private void handleOnConfirmDeviceCredentialError(int error, String message) {
if (mConfirmDeviceCredentialReceiver == null) {
- Slog.w(TAG, "onCDCAError null! Error: " + error + " " + message);
+ Slog.w(TAG, "handleOnConfirmDeviceCredentialError null! Error: "
+ + error + " " + message);
return;
}
try {
- mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
mConfirmDeviceCredentialReceiver.onError(error, message);
if (mCurrentAuthSession != null) {
- mCurrentAuthSession.mState = STATE_AUTH_IDLE;
mCurrentAuthSession = null;
}
} catch (RemoteException e) {
@@ -1272,7 +1314,7 @@
}
private void handleOnError(int cookie, int error, String message) {
- Slog.d(TAG, "Error: " + error + " cookie: " + cookie);
+ Slog.d(TAG, "handleOnError: " + error + " cookie: " + cookie);
// Errors can either be from the current auth session or the pending auth session.
// The pending auth session may receive errors such as ERROR_LOCKOUT before
// it becomes the current auth session. Similarly, the current auth session may
@@ -1282,6 +1324,9 @@
try {
if (mCurrentAuthSession != null && mCurrentAuthSession.containsCookie(cookie)) {
+ mCurrentAuthSession.mErrorEscrow = error;
+ mCurrentAuthSession.mErrorStringEscrow = message;
+
if (mCurrentAuthSession.isFromConfirmDeviceCredential()) {
// If we were invoked by ConfirmDeviceCredential, do not delete the current
// auth session since we still need to respond to cancel signal while
@@ -1293,39 +1338,18 @@
mCurrentAuthSession.mState = STATE_BIOMETRIC_AUTH_CANCELED_SHOWING_CDC;
mStatusBarService.hideBiometricDialog();
} else if (mCurrentAuthSession.mState == STATE_AUTH_STARTED) {
- mStatusBarService.onBiometricError(message);
+ mCurrentAuthSession.mState = STATE_ERROR_PENDING_SYSUI;
if (error == BiometricConstants.BIOMETRIC_ERROR_CANCELED) {
- mActivityTaskManager.unregisterTaskStackListener(
- mTaskStackListener);
- mCurrentAuthSession.mClientReceiver.onError(error, message);
- mCurrentAuthSession.mState = STATE_AUTH_IDLE;
- mCurrentAuthSession = null;
mStatusBarService.hideBiometricDialog();
} else {
- // Send errors after the dialog is dismissed.
- mHandler.postDelayed(() -> {
- try {
- if (mCurrentAuthSession != null) {
- mActivityTaskManager.unregisterTaskStackListener(
- mTaskStackListener);
- mCurrentAuthSession.mClientReceiver.onError(error,
- message);
- mCurrentAuthSession.mState = STATE_AUTH_IDLE;
- mCurrentAuthSession = null;
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception", e);
- }
- }, BiometricPrompt.HIDE_DIALOG_DELAY);
+ mStatusBarService.onBiometricError(message);
}
} else if (mCurrentAuthSession.mState == STATE_AUTH_PAUSED) {
// In the "try again" state, we should forward canceled errors to
- // the client and and clean up.
+ // the client and and clean up. The only error we should get here is
+ // ERROR_CANCELED due to another client kicking us out.
mCurrentAuthSession.mClientReceiver.onError(error, message);
- mStatusBarService.onBiometricError(message);
- mActivityTaskManager.unregisterTaskStackListener(
- mTaskStackListener);
- mCurrentAuthSession.mState = STATE_AUTH_IDLE;
+ mStatusBarService.hideBiometricDialog();
mCurrentAuthSession = null;
} else {
Slog.e(TAG, "Impossible session error state: "
@@ -1335,7 +1359,6 @@
&& mPendingAuthSession.containsCookie(cookie)) {
if (mPendingAuthSession.mState == STATE_AUTH_CALLED) {
mPendingAuthSession.mClientReceiver.onError(error, message);
- mPendingAuthSession.mState = STATE_AUTH_IDLE;
mPendingAuthSession = null;
} else {
Slog.e(TAG, "Impossible pending session error state: "
@@ -1370,42 +1393,50 @@
private void handleOnDismissed(int reason) {
if (mCurrentAuthSession == null) {
- Slog.e(TAG, "onDialogDismissed: " + reason + ", auth session null");
+ Slog.e(TAG, "onDismissed: " + reason + ", auth session null");
return;
}
logDialogDismissed(reason);
try {
- if (reason != BiometricPrompt.DISMISSED_REASON_POSITIVE) {
- // Positive button is used by passive modalities as a "confirm" button,
- // do not send to client
- mCurrentAuthSession.mClientReceiver.onDialogDismissed(reason);
- // Cancel authentication. Skip the token/package check since we are cancelling
- // from system server. The interface is permission protected so this is fine.
- cancelInternal(null /* token */, null /* package */, false /* fromClient */);
- }
- if (reason == BiometricPrompt.DISMISSED_REASON_USER_CANCEL) {
- mCurrentAuthSession.mClientReceiver.onError(
- BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED,
- getContext().getString(
- com.android.internal.R.string.biometric_error_user_canceled));
- } else if (reason == BiometricPrompt.DISMISSED_REASON_POSITIVE) {
- // Have the service send the token to KeyStore, and send onAuthenticated
- // to the application
- KeyStore.getInstance().addAuthToken(mCurrentAuthSession.mTokenEscrow);
- mCurrentAuthSession.mClientReceiver.onAuthenticationSucceeded();
+ switch (reason) {
+ case BiometricPrompt.DISMISSED_REASON_CONFIRMED:
+ case BiometricPrompt.DISMISSED_REASON_CONFIRM_NOT_REQUIRED:
+ mKeyStore.addAuthToken(mCurrentAuthSession.mTokenEscrow);
+ mCurrentAuthSession.mClientReceiver.onAuthenticationSucceeded();
+ break;
+
+ case BiometricPrompt.DISMISSED_REASON_NEGATIVE:
+ mCurrentAuthSession.mClientReceiver.onDialogDismissed(reason);
+ // Cancel authentication. Skip the token/package check since we are cancelling
+ // from system server. The interface is permission protected so this is fine.
+ cancelInternal(null /* token */, null /* package */, false /* fromClient */);
+ break;
+
+ case BiometricPrompt.DISMISSED_REASON_USER_CANCEL:
+ mCurrentAuthSession.mClientReceiver.onError(
+ BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED,
+ getContext().getString(R.string.biometric_error_user_canceled));
+ // Cancel authentication. Skip the token/package check since we are cancelling
+ // from system server. The interface is permission protected so this is fine.
+ cancelInternal(null /* token */, null /* package */, false /* fromClient */);
+ break;
+
+ case BiometricPrompt.DISMISSED_REASON_SERVER_REQUESTED:
+ case BiometricPrompt.DISMISSED_REASON_ERROR:
+ mCurrentAuthSession.mClientReceiver.onError(mCurrentAuthSession.mErrorEscrow,
+ mCurrentAuthSession.mErrorStringEscrow);
+ break;
+
+ default:
+ Slog.w(TAG, "Unhandled reason: " + reason);
+ break;
}
- // Do not clean up yet if we are from ConfirmDeviceCredential. We should be in the
- // STATE_BIOMETRIC_AUTH_CANCELED_SHOWING_CDC. The session should only be removed when
- // ConfirmDeviceCredential is confirmed or canceled.
- // TODO(b/123378871): Remove when moved
- if (!mCurrentAuthSession.isFromConfirmDeviceCredential()) {
- mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
- mCurrentAuthSession.mState = STATE_AUTH_IDLE;
- mCurrentAuthSession = null;
- }
+ // Dialog is gone, auth session is done.
+ mCurrentAuthSession = null;
+
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception", e);
}
@@ -1472,8 +1503,8 @@
if (!continuing) {
mStatusBarService.showBiometricDialog(mCurrentAuthSession.mBundle,
- mInternalReceiver, modality, requireConfirmation, userId);
- mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
+ mInternalReceiver, modality, requireConfirmation, userId,
+ mCurrentAuthSession.mOpPackageName);
}
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception", e);
@@ -1517,8 +1548,6 @@
return;
}
- mCurrentModality = modality;
-
// Start preparing for authentication. Authentication starts when
// all modalities requested have invoked onReadyForAuthentication.
authenticateInternal(token, sessionId, userId, receiver, opPackageName, bundle,
@@ -1610,7 +1639,6 @@
com.android.internal.R.string.biometric_error_user_canceled)
);
- mCurrentAuthSession.mState = STATE_AUTH_IDLE;
mCurrentAuthSession = null;
mStatusBarService.hideBiometricDialog();
} catch (RemoteException e) {
@@ -1637,25 +1665,31 @@
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
final int callingUserId = UserHandle.getCallingUserId();
- mHandler.post(() -> {
- try {
- // TODO: For multiple modalities, send a single ERROR_CANCELED only when all
- // drivers have canceled authentication.
- if ((mCurrentModality & TYPE_FINGERPRINT) != 0) {
- mFingerprintService.cancelAuthenticationFromService(token, opPackageName,
- callingUid, callingPid, callingUserId, fromClient);
- }
- if ((mCurrentModality & TYPE_IRIS) != 0) {
- Slog.w(TAG, "Iris unsupported");
- }
- if ((mCurrentModality & TYPE_FACE) != 0) {
- mFaceService.cancelAuthenticationFromService(token, opPackageName,
- callingUid, callingPid, callingUserId, fromClient);
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to cancel authentication");
- }
- });
- }
+ try {
+ if (mCurrentAuthSession == null) {
+ Slog.w(TAG, "Skipping cancelInternal");
+ return;
+ } else if (mCurrentAuthSession.mState != STATE_AUTH_STARTED) {
+ Slog.w(TAG, "Skipping cancelInternal, state: " + mCurrentAuthSession.mState);
+ return;
+ }
+
+ // TODO: For multiple modalities, send a single ERROR_CANCELED only when all
+ // drivers have canceled authentication.
+ if ((mCurrentAuthSession.mModality & TYPE_FINGERPRINT) != 0) {
+ mFingerprintService.cancelAuthenticationFromService(token, opPackageName,
+ callingUid, callingPid, callingUserId, fromClient);
+ }
+ if ((mCurrentAuthSession.mModality & TYPE_IRIS) != 0) {
+ Slog.w(TAG, "Iris unsupported");
+ }
+ if ((mCurrentAuthSession.mModality & TYPE_FACE) != 0) {
+ mFaceService.cancelAuthenticationFromService(token, opPackageName,
+ callingUid, callingPid, callingUserId, fromClient);
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to cancel authentication");
+ }
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
index f3f9754..2de18c3 100644
--- a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
+++ b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
@@ -420,7 +420,7 @@
throw new UnsupportedOperationException("Stub!");
}
- default void onAuthenticationFailedInternal(int cookie, boolean requireConfirmation)
+ default void onAuthenticationFailedInternal()
throws RemoteException {
throw new UnsupportedOperationException("Stub!");
}
@@ -457,10 +457,10 @@
}
@Override
- public void onAuthenticationFailedInternal(int cookie, boolean requireConfirmation)
+ public void onAuthenticationFailedInternal()
throws RemoteException {
if (getWrapperReceiver() != null) {
- getWrapperReceiver().onAuthenticationFailed(cookie, requireConfirmation);
+ getWrapperReceiver().onAuthenticationFailed();
}
}
}
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
index 53890a4..a0eafb4 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
@@ -35,6 +35,8 @@
import android.hardware.broadcastradio.V2_0.VendorKeyValue;
import android.hardware.radio.RadioManager;
import android.os.DeadObjectException;
+import android.os.Handler;
+import android.os.Looper;
import android.os.RemoteException;
import android.util.MutableInt;
import android.util.Slog;
@@ -45,6 +47,7 @@
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
@@ -56,6 +59,7 @@
@NonNull public final RadioManager.ModuleProperties mProperties;
private final Object mLock = new Object();
+ @NonNull private final Handler mHandler;
@GuardedBy("mLock")
private ITunerSession mHalTunerSession;
@@ -77,22 +81,24 @@
private final ITunerCallback mHalTunerCallback = new ITunerCallback.Stub() {
@Override
public void onTuneFailed(int result, ProgramSelector programSelector) {
- fanoutAidlCallback(cb -> cb.onTuneFailed(result, Convert.programSelectorFromHal(
- programSelector)));
+ lockAndFireLater(() -> {
+ android.hardware.radio.ProgramSelector csel =
+ Convert.programSelectorFromHal(programSelector);
+ fanoutAidlCallbackLocked(cb -> cb.onTuneFailed(result, csel));
+ });
}
@Override
public void onCurrentProgramInfoChanged(ProgramInfo halProgramInfo) {
- RadioManager.ProgramInfo programInfo = Convert.programInfoFromHal(halProgramInfo);
- synchronized (mLock) {
- mCurrentProgramInfo = programInfo;
- fanoutAidlCallbackLocked(cb -> cb.onCurrentProgramInfoChanged(programInfo));
- }
+ lockAndFireLater(() -> {
+ mCurrentProgramInfo = Convert.programInfoFromHal(halProgramInfo);
+ fanoutAidlCallbackLocked(cb -> cb.onCurrentProgramInfoChanged(mCurrentProgramInfo));
+ });
}
@Override
public void onProgramListUpdated(ProgramListChunk programListChunk) {
- synchronized (mLock) {
+ lockAndFireLater(() -> {
android.hardware.radio.ProgramList.Chunk chunk =
Convert.programListChunkFromHal(programListChunk);
mProgramInfoCache.filterAndApplyChunk(chunk);
@@ -100,20 +106,23 @@
for (TunerSession tunerSession : mAidlTunerSessions) {
tunerSession.onMergedProgramListUpdateFromHal(chunk);
}
- }
+ });
}
@Override
public void onAntennaStateChange(boolean connected) {
- synchronized (mLock) {
+ lockAndFireLater(() -> {
mAntennaConnected = connected;
fanoutAidlCallbackLocked(cb -> cb.onAntennaState(connected));
- }
+ });
}
@Override
public void onParametersUpdated(ArrayList<VendorKeyValue> parameters) {
- fanoutAidlCallback(cb -> cb.onParametersUpdated(Convert.vendorInfoFromHal(parameters)));
+ lockAndFireLater(() -> {
+ Map<String, String> cparam = Convert.vendorInfoFromHal(parameters);
+ fanoutAidlCallbackLocked(cb -> cb.onParametersUpdated(cparam));
+ });
}
};
@@ -126,6 +135,7 @@
@NonNull RadioManager.ModuleProperties properties) {
mProperties = Objects.requireNonNull(properties);
mService = Objects.requireNonNull(service);
+ mHandler = new Handler(Looper.getMainLooper());
}
public static @Nullable RadioModule tryLoadingModule(int idx, @NonNull String fqName) {
@@ -310,15 +320,22 @@
}
}
+ // add to mHandler queue, but ensure the runnable holds mLock when it gets executed
+ private void lockAndFireLater(Runnable r) {
+ mHandler.post(() -> {
+ synchronized (mLock) {
+ r.run();
+ }
+ });
+ }
+
interface AidlCallbackRunnable {
void run(android.hardware.radio.ITunerCallback callback) throws RemoteException;
}
// Invokes runnable with each TunerSession currently open.
void fanoutAidlCallback(AidlCallbackRunnable runnable) {
- synchronized (mLock) {
- fanoutAidlCallbackLocked(runnable);
- }
+ lockAndFireLater(() -> fanoutAidlCallbackLocked(runnable));
}
private void fanoutAidlCallbackLocked(AidlCallbackRunnable runnable) {
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index 3eea194..27050fa 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -16,6 +16,7 @@
package com.android.server.compat;
+import android.compat.IPlatformCompat;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.util.Slog;
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 73d160d..86d1212 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -1314,11 +1314,15 @@
mOffload.excludeDownstreamInterface(who.interfaceName());
mForwardedDownstreams.remove(who);
- // If this is a Wi-Fi interface, tell WifiManager of any errors.
+ // If this is a Wi-Fi interface, tell WifiManager of any errors
+ // or the inactive serving state.
if (who.interfaceType() == TETHERING_WIFI) {
if (who.lastError() != TETHER_ERROR_NO_ERROR) {
getWifiManager().updateInterfaceIpState(
who.interfaceName(), IFACE_IP_MODE_CONFIGURATION_ERROR);
+ } else {
+ getWifiManager().updateInterfaceIpState(
+ who.interfaceName(), IFACE_IP_MODE_UNSPECIFIED);
}
}
}
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index e7a8b13..fb94907 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -95,7 +95,7 @@
import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.util.ArrayUtils;
import com.android.server.ConnectivityService;
-import com.android.server.DeviceIdleController;
+import com.android.server.DeviceIdleInternal;
import com.android.server.LocalServices;
import com.android.server.net.BaseNetworkObserver;
@@ -616,8 +616,8 @@
// a short time, so we can bootstrap the VPN service.
final long oldId = Binder.clearCallingIdentity();
try {
- DeviceIdleController.LocalService idleController =
- LocalServices.getService(DeviceIdleController.LocalService.class);
+ DeviceIdleInternal idleController =
+ LocalServices.getService(DeviceIdleInternal.class);
idleController.addPowerSaveTempWhitelistApp(Process.myUid(), alwaysOnPackage,
VPN_LAUNCH_IDLE_WHITELIST_DURATION_MS, mUserHandle, false, "vpn");
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index f6c49ed..e7f537b 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -102,7 +102,7 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.function.QuadConsumer;
-import com.android.server.DeviceIdleController;
+import com.android.server.DeviceIdleInternal;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.accounts.AccountManagerService;
@@ -1634,8 +1634,8 @@
if (syncOperation.syncExemptionFlag
== ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP) {
- DeviceIdleController.LocalService dic =
- LocalServices.getService(DeviceIdleController.LocalService.class);
+ DeviceIdleInternal dic =
+ LocalServices.getService(DeviceIdleInternal.class);
if (dic != null) {
dic.addPowerSaveTempWhitelistApp(Process.SYSTEM_UID,
syncOperation.owningPackage,
diff --git a/services/core/java/com/android/server/deviceidle/BluetoothConstraint.java b/services/core/java/com/android/server/deviceidle/BluetoothConstraint.java
index cc319bf..731d899 100644
--- a/services/core/java/com/android/server/deviceidle/BluetoothConstraint.java
+++ b/services/core/java/com/android/server/deviceidle/BluetoothConstraint.java
@@ -29,7 +29,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.DeviceIdleController;
+import com.android.server.DeviceIdleInternal;
/**
* Track whether there are any active Bluetooth devices connected.
@@ -40,14 +40,14 @@
private final Context mContext;
private final Handler mHandler;
- private final DeviceIdleController.LocalService mLocalService;
+ private final DeviceIdleInternal mLocalService;
private final BluetoothManager mBluetoothManager;
private volatile boolean mConnected = true;
private volatile boolean mMonitoring = false;
public BluetoothConstraint(
- Context context, Handler handler, DeviceIdleController.LocalService localService) {
+ Context context, Handler handler, DeviceIdleInternal localService) {
mContext = context;
mHandler = handler;
mLocalService = localService;
diff --git a/services/core/java/com/android/server/deviceidle/TvConstraintController.java b/services/core/java/com/android/server/deviceidle/TvConstraintController.java
index 2d472de6..7f0a271 100644
--- a/services/core/java/com/android/server/deviceidle/TvConstraintController.java
+++ b/services/core/java/com/android/server/deviceidle/TvConstraintController.java
@@ -21,7 +21,7 @@
import android.content.pm.PackageManager;
import android.os.Handler;
-import com.android.server.DeviceIdleController;
+import com.android.server.DeviceIdleInternal;
import com.android.server.LocalServices;
/**
@@ -33,7 +33,7 @@
public class TvConstraintController implements ConstraintController {
private final Context mContext;
private final Handler mHandler;
- private final DeviceIdleController.LocalService mDeviceIdleService;
+ private final DeviceIdleInternal mDeviceIdleService;
@Nullable
private final BluetoothConstraint mBluetoothConstraint;
@@ -41,7 +41,7 @@
public TvConstraintController(Context context, Handler handler) {
mContext = context;
mHandler = handler;
- mDeviceIdleService = LocalServices.getService(DeviceIdleController.LocalService.class);
+ mDeviceIdleService = LocalServices.getService(DeviceIdleInternal.class);
final PackageManager pm = context.getPackageManager();
mBluetoothConstraint = pm.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)
diff --git a/services/core/java/com/android/server/display/WifiDisplayController.java b/services/core/java/com/android/server/display/WifiDisplayController.java
index fc59b5b..d9d46b8 100644
--- a/services/core/java/com/android/server/display/WifiDisplayController.java
+++ b/services/core/java/com/android/server/display/WifiDisplayController.java
@@ -94,8 +94,8 @@
private final Handler mHandler;
private final Listener mListener;
- private final WifiP2pManager mWifiP2pManager;
- private final Channel mWifiP2pChannel;
+ private WifiP2pManager mWifiP2pManager;
+ private Channel mWifiP2pChannel;
private boolean mWifiP2pEnabled;
private boolean mWfdEnabled;
@@ -164,9 +164,6 @@
mHandler = handler;
mListener = listener;
- mWifiP2pManager = (WifiP2pManager)context.getSystemService(Context.WIFI_P2P_SERVICE);
- mWifiP2pChannel = mWifiP2pManager.initialize(context, handler.getLooper(), null);
-
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
@@ -191,6 +188,18 @@
updateSettings();
}
+ /**
+ * Used to lazily retrieve WifiP2pManager service.
+ */
+ private void retrieveWifiP2pManagerAndChannel() {
+ if (mWifiP2pManager == null) {
+ mWifiP2pManager = (WifiP2pManager)mContext.getSystemService(Context.WIFI_P2P_SERVICE);
+ }
+ if (mWifiP2pChannel == null && mWifiP2pManager != null) {
+ mWifiP2pChannel = mWifiP2pManager.initialize(mContext, mHandler.getLooper(), null);
+ }
+ }
+
private void updateSettings() {
final ContentResolver resolver = mContext.getContentResolver();
mWifiDisplayOnSetting = Settings.Global.getInt(resolver,
@@ -803,6 +812,9 @@
private void handleStateChanged(boolean enabled) {
mWifiP2pEnabled = enabled;
+ if (enabled) {
+ retrieveWifiP2pManagerAndChannel();
+ }
updateWfdEnableState();
}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index f1f6d50..f38f2f9 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -106,6 +106,7 @@
import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.internal.widget.ICheckCredentialProgressCallback;
import com.android.internal.widget.ILockSettings;
@@ -137,8 +138,10 @@
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
@@ -169,6 +172,8 @@
private static final int PROFILE_KEY_IV_SIZE = 12;
private static final String SEPARATE_PROFILE_CHALLENGE_KEY = "lockscreen.profilechallenge";
private static final int SYNTHETIC_PASSWORD_ENABLED_BY_DEFAULT = 1;
+ private static final String PREV_SYNTHETIC_PASSWORD_HANDLE_KEY = "prev-sp-handle";
+ private static final String SYNTHETIC_PASSWORD_UPDATE_TIME_KEY = "sp-handle-ts";
// No challenge provided
private static final int CHALLENGE_NONE = 0;
@@ -357,7 +362,7 @@
setLong(LockPatternUtils.PASSWORD_TYPE_KEY, quality, managedUserId);
tieProfileLockToParent(managedUserId, newPassword);
Arrays.fill(newPassword, (byte) 0);
- } catch (NoSuchAlgorithmException | RemoteException e) {
+ } catch (NoSuchAlgorithmException e) {
Slog.e(TAG, "Fail to tie managed profile", e);
// Nothing client can do to fix this issue, so we do not throw exception out
}
@@ -604,15 +609,11 @@
if (ks.state(userId) == KeyStore.State.LOCKED
&& tiedManagedProfileReadyToUnlock(mUserManager.getUserInfo(userId))) {
Slog.i(TAG, "Managed profile got unlocked, will unlock its keystore");
- try {
- // If boot took too long and the password in vold got expired, parent keystore will
- // be still locked, we ignore this case since the user will be prompted to unlock
- // the device after boot.
- unlockChildProfile(userId, true /* ignoreUserNotAuthenticated */,
- CHALLENGE_NONE, 0 /* challenge */, null /* resetLockouts */);
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to unlock child profile");
- }
+ // If boot took too long and the password in vold got expired, parent keystore will
+ // be still locked, we ignore this case since the user will be prompted to unlock
+ // the device after boot.
+ unlockChildProfile(userId, true /* ignoreUserNotAuthenticated */,
+ CHALLENGE_NONE, 0 /* challenge */, null /* resetLockouts */);
}
}
@@ -648,20 +649,16 @@
return;
}
- try {
- final long handle = getSyntheticPasswordHandleLocked(userId);
- final byte[] noCredential = null;
- AuthenticationResult result =
- mSpManager.unwrapPasswordBasedSyntheticPassword(
- getGateKeeperService(), handle, noCredential, userId, null);
- if (result.authToken != null) {
- Slog.i(TAG, "Retrieved auth token for user " + userId);
- onAuthTokenKnownForUser(userId, result.authToken);
- } else {
- Slog.e(TAG, "Auth token not available for user " + userId);
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Failure retrieving auth token", e);
+ final long handle = getSyntheticPasswordHandleLocked(userId);
+ final byte[] noCredential = null;
+ AuthenticationResult result =
+ mSpManager.unwrapPasswordBasedSyntheticPassword(
+ getGateKeeperService(), handle, noCredential, userId, null);
+ if (result.authToken != null) {
+ Slog.i(TAG, "Retrieved auth token for user " + userId);
+ onAuthTokenKnownForUser(userId, result.authToken);
+ } else {
+ Slog.e(TAG, "Auth token not available for user " + userId);
}
}
}
@@ -698,12 +695,8 @@
}
checkWritePermission(UserHandle.USER_SYSTEM);
migrateOldData();
- try {
- getGateKeeperService();
- mSpManager.initWeaverService();
- } catch (RemoteException e) {
- Slog.e(TAG, "Failure retrieving IGateKeeperService", e);
- }
+ getGateKeeperService();
+ mSpManager.initWeaverService();
// Find the AuthSecret HAL
try {
mAuthSecretService = IAuthSecret.getService();
@@ -872,16 +865,12 @@
}
private void migrateOldDataAfterSystemReady() {
- try {
- // Migrate the FRP credential to the persistent data block
- if (LockPatternUtils.frpCredentialEnabled(mContext)
- && !getBoolean("migrated_frp", false, 0)) {
- migrateFrpCredential();
- setBoolean("migrated_frp", true, 0);
- Slog.i(TAG, "Migrated migrated_frp.");
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to migrateOldDataAfterSystemReady", e);
+ // Migrate the FRP credential to the persistent data block
+ if (LockPatternUtils.frpCredentialEnabled(mContext)
+ && !getBoolean("migrated_frp", false, 0)) {
+ migrateFrpCredential();
+ setBoolean("migrated_frp", true, 0);
+ Slog.i(TAG, "Migrated migrated_frp.");
}
}
@@ -891,7 +880,7 @@
* - the FRP credential is not set up
* - the credential is based on a synthetic password.
*/
- private void migrateFrpCredential() throws RemoteException {
+ private void migrateFrpCredential() {
if (mStorage.readPersistentDataBlock() != PersistentData.NONE) {
return;
}
@@ -1187,8 +1176,7 @@
private void unlockChildProfile(int profileHandle, boolean ignoreUserNotAuthenticated,
@ChallengeType int challengeType, long challenge,
- @Nullable ArrayList<PendingResetLockout> resetLockouts)
- throws RemoteException {
+ @Nullable ArrayList<PendingResetLockout> resetLockouts) {
try {
doVerifyCredential(getDecryptedPasswordForTiedProfile(profileHandle),
CREDENTIAL_TYPE_PASSWORD,
@@ -1263,14 +1251,10 @@
for (UserInfo profile : mUserManager.getProfiles(userId)) {
// Unlock managed profile with unified lock
if (tiedManagedProfileReadyToUnlock(profile)) {
- try {
- // Must pass the challenge on for resetLockout, so it's not over-written, which
- // causes LockSettingsService to revokeChallenge inappropriately.
- unlockChildProfile(profile.id, false /* ignoreUserNotAuthenticated */,
- challengeType, challenge, resetLockouts);
- } catch (RemoteException e) {
- Log.d(TAG, "Failed to unlock child profile", e);
- }
+ // Must pass the challenge on for resetLockout, so it's not over-written, which
+ // causes LockSettingsService to revokeChallenge inappropriately.
+ unlockChildProfile(profile.id, false /* ignoreUserNotAuthenticated */,
+ challengeType, challenge, resetLockouts);
}
// Now we have unlocked the parent user and attempted to unlock the profile we should
// show notifications if the profile is still locked.
@@ -1350,7 +1334,7 @@
* terminates when the user is a managed profile.
*/
private void synchronizeUnifiedWorkChallengeForProfiles(int userId,
- Map<Integer, byte[]> profilePasswordMap) throws RemoteException {
+ Map<Integer, byte[]> profilePasswordMap) {
if (mUserManager.getUserInfo(userId).isManagedProfile()) {
return;
}
@@ -1464,7 +1448,7 @@
@Override
public void setLockCredential(byte[] credential, int type,
byte[] savedCredential, int requestedQuality, int userId,
- boolean allowUntrustedChange) throws RemoteException {
+ boolean allowUntrustedChange) {
if (!mLockPatternUtils.hasSecureLockScreen()) {
throw new UnsupportedOperationException(
@@ -1490,7 +1474,7 @@
*/
private void setLockCredentialInternal(byte[] credential, @CredentialType int credentialType,
byte[] savedCredential, int requestedQuality, int userId, boolean allowUntrustedChange,
- boolean isLockTiedToParent) throws RemoteException {
+ boolean isLockTiedToParent) {
// Normalize savedCredential and credential such that empty string is always represented
// as null.
if (savedCredential == null || savedCredential.length == 0) {
@@ -1512,7 +1496,7 @@
Slog.wtf(TAG, "CredentialType is none, but credential is non-null.");
}
clearUserKeyProtection(userId);
- getGateKeeperService().clearSecureUserId(userId);
+ gateKeeperClearSecureUserId(userId);
mStorage.writeCredentialHash(CredentialHash.createEmptyHash(), userId);
setKeystorePassword(null, userId);
fixateNewestUserKeyAuth(userId);
@@ -1523,7 +1507,7 @@
return;
}
if (credential == null) {
- throw new RemoteException("Null credential with mismatched credential type");
+ throw new IllegalArgumentException("Null credential with mismatched credential type");
}
CredentialHash currentHandle = mStorage.readCredentialHash(userId);
@@ -1565,8 +1549,13 @@
CredentialHash willStore = CredentialHash.create(enrolledHandle, credentialType);
mStorage.writeCredentialHash(willStore, userId);
// push new secret and auth token to vold
- GateKeeperResponse gkResponse = getGateKeeperService()
- .verifyChallenge(userId, 0, willStore.hash, credential);
+ GateKeeperResponse gkResponse;
+ try {
+ gkResponse = getGateKeeperService().verifyChallenge(userId, 0, willStore.hash,
+ credential);
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Failed to verify current credential", e);
+ }
setUserKeyProtection(userId, credential, convertResponse(gkResponse));
fixateNewestUserKeyAuth(userId);
// Refresh the auth token
@@ -1576,8 +1565,8 @@
sendCredentialsOnChangeIfRequired(
credentialType, credential, userId, isLockTiedToParent);
} else {
- throw new RemoteException("Failed to enroll " +
- (credentialType == CREDENTIAL_TYPE_PASSWORD ? "password" : "pattern"));
+ throw new IllegalStateException(String.format("Failed to enroll %s",
+ credentialType == CREDENTIAL_TYPE_PASSWORD ? "password" : "pattern"));
}
}
@@ -1630,27 +1619,32 @@
} catch (CertificateException | UnrecoverableKeyException
| IOException | BadPaddingException | IllegalBlockSizeException | KeyStoreException
| NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException e) {
- throw new RuntimeException("Failed to encrypt key", e);
+ throw new IllegalStateException("Failed to encrypt key", e);
}
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try {
if (iv.length != PROFILE_KEY_IV_SIZE) {
- throw new RuntimeException("Invalid iv length: " + iv.length);
+ throw new IllegalArgumentException("Invalid iv length: " + iv.length);
}
outputStream.write(iv);
outputStream.write(encryptionResult);
} catch (IOException e) {
- throw new RuntimeException("Failed to concatenate byte arrays", e);
+ throw new IllegalStateException("Failed to concatenate byte arrays", e);
}
mStorage.writeChildProfileLock(userId, outputStream.toByteArray());
}
private byte[] enrollCredential(byte[] enrolledHandle,
- byte[] enrolledCredential, byte[] toEnroll, int userId)
- throws RemoteException {
+ byte[] enrolledCredential, byte[] toEnroll, int userId) {
checkWritePermission(userId);
- GateKeeperResponse response = getGateKeeperService().enroll(userId, enrolledHandle,
- enrolledCredential, toEnroll);
+ GateKeeperResponse response;
+ try {
+ response = getGateKeeperService().enroll(userId, enrolledHandle,
+ enrolledCredential, toEnroll);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to enroll credential", e);
+ return null;
+ }
if (response == null) {
return null;
@@ -1666,34 +1660,33 @@
return hash;
}
- private void setAuthlessUserKeyProtection(int userId, byte[] key) throws RemoteException {
+ private void setAuthlessUserKeyProtection(int userId, byte[] key) {
if (DEBUG) Slog.d(TAG, "setAuthlessUserKeyProtectiond: user=" + userId);
addUserKeyAuth(userId, null, key);
}
- private void setUserKeyProtection(int userId, byte[] credential, VerifyCredentialResponse vcr)
- throws RemoteException {
+ private void setUserKeyProtection(int userId, byte[] credential, VerifyCredentialResponse vcr) {
if (DEBUG) Slog.d(TAG, "setUserKeyProtection: user=" + userId);
if (vcr == null) {
- throw new RemoteException("Null response verifying a credential we just set");
+ throw new IllegalArgumentException("Null response verifying a credential we just set");
}
if (vcr.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
- throw new RemoteException("Non-OK response verifying a credential we just set: "
+ throw new IllegalArgumentException("Non-OK response verifying a credential we just set "
+ vcr.getResponseCode());
}
byte[] token = vcr.getPayload();
if (token == null) {
- throw new RemoteException("Empty payload verifying a credential we just set");
+ throw new IllegalArgumentException("Empty payload verifying a credential we just set");
}
addUserKeyAuth(userId, token, secretFromCredential(credential));
}
- private void clearUserKeyProtection(int userId) throws RemoteException {
+ private void clearUserKeyProtection(int userId) {
if (DEBUG) Slog.d(TAG, "clearUserKeyProtection user=" + userId);
addUserKeyAuth(userId, null, null);
}
- private static byte[] secretFromCredential(byte[] credential) throws RemoteException {
+ private static byte[] secretFromCredential(byte[] credential) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-512");
// Personalize the hash
@@ -1704,7 +1697,7 @@
digest.update(credential);
return digest.digest();
} catch (NoSuchAlgorithmException e) {
- throw new RuntimeException("NoSuchAlgorithmException for SHA-512");
+ throw new IllegalStateException("NoSuchAlgorithmException for SHA-512");
}
}
@@ -1718,35 +1711,44 @@
}
/** Unlock disk encryption */
- private void unlockUserKey(int userId, byte[] token, byte[] secret) throws RemoteException {
+ private void unlockUserKey(int userId, byte[] token, byte[] secret) {
final UserInfo userInfo = mUserManager.getUserInfo(userId);
- mStorageManager.unlockUserKey(userId, userInfo.serialNumber, token, secret);
+ try {
+ mStorageManager.unlockUserKey(userId, userInfo.serialNumber, token, secret);
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Failed to unlock user key " + userId, e);
+
+ }
}
- private void addUserKeyAuth(int userId, byte[] token, byte[] secret)
- throws RemoteException {
+ private void addUserKeyAuth(int userId, byte[] token, byte[] secret) {
final UserInfo userInfo = mUserManager.getUserInfo(userId);
final long callingId = Binder.clearCallingIdentity();
try {
mStorageManager.addUserKeyAuth(userId, userInfo.serialNumber, token, secret);
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Failed to add new key to vold " + userId, e);
} finally {
Binder.restoreCallingIdentity(callingId);
}
}
- private void fixateNewestUserKeyAuth(int userId)
- throws RemoteException {
+ private void fixateNewestUserKeyAuth(int userId) {
if (DEBUG) Slog.d(TAG, "fixateNewestUserKeyAuth: user=" + userId);
final long callingId = Binder.clearCallingIdentity();
try {
mStorageManager.fixateNewestUserKeyAuth(userId);
+ } catch (RemoteException e) {
+ // OK to ignore the exception as vold would just accept both old and new
+ // keys if this call fails, and will fix itself during the next boot
+ Slog.w(TAG, "fixateNewestUserKeyAuth failed", e);
} finally {
Binder.restoreCallingIdentity(callingId);
}
}
@Override
- public void resetKeyStore(int userId) throws RemoteException {
+ public void resetKeyStore(int userId) {
checkWritePermission(userId);
if (DEBUG) Slog.v(TAG, "Reset keystore for user: " + userId);
int managedUserId = -1;
@@ -1794,14 +1796,14 @@
@Override
public VerifyCredentialResponse checkCredential(byte[] credential, int type, int userId,
- ICheckCredentialProgressCallback progressCallback) throws RemoteException {
+ ICheckCredentialProgressCallback progressCallback) {
checkPasswordReadPermission(userId);
return doVerifyCredential(credential, type, CHALLENGE_NONE, 0, userId, progressCallback);
}
@Override
public VerifyCredentialResponse verifyCredential(byte[] credential, int type, long challenge,
- int userId) throws RemoteException {
+ int userId) {
checkPasswordReadPermission(userId);
return doVerifyCredential(credential, type, CHALLENGE_FROM_CALLER, challenge, userId,
null /* progressCallback */);
@@ -1809,7 +1811,7 @@
private VerifyCredentialResponse doVerifyCredential(byte[] credential, int credentialType,
@ChallengeType int challengeType, long challenge, int userId,
- ICheckCredentialProgressCallback progressCallback) throws RemoteException {
+ ICheckCredentialProgressCallback progressCallback) {
return doVerifyCredential(credential, credentialType, challengeType, challenge, userId,
progressCallback, null /* resetLockouts */);
}
@@ -1821,7 +1823,7 @@
private VerifyCredentialResponse doVerifyCredential(byte[] credential, int credentialType,
@ChallengeType int challengeType, long challenge, int userId,
ICheckCredentialProgressCallback progressCallback,
- @Nullable ArrayList<PendingResetLockout> resetLockouts) throws RemoteException {
+ @Nullable ArrayList<PendingResetLockout> resetLockouts) {
if (credential == null || credential.length == 0) {
throw new IllegalArgumentException("Credential can't be null or empty");
}
@@ -1865,10 +1867,10 @@
@Override
public VerifyCredentialResponse verifyTiedProfileChallenge(byte[] credential, int type,
- long challenge, int userId) throws RemoteException {
+ long challenge, int userId) {
checkPasswordReadPermission(userId);
if (!isManagedProfileWithUnifiedLock(userId)) {
- throw new RemoteException("User id must be managed profile with unified lock");
+ throw new IllegalArgumentException("User id must be managed profile with unified lock");
}
final int parentProfileId = mUserManager.getProfileParent(userId).id;
// Unlock parent by using parent's challenge
@@ -1896,7 +1898,7 @@
| InvalidAlgorithmParameterException | IllegalBlockSizeException
| BadPaddingException | CertificateException | IOException e) {
Slog.e(TAG, "Failed to decrypt child profile key", e);
- throw new RemoteException("Unable to get tied profile token");
+ throw new IllegalStateException("Unable to get tied profile token");
}
}
@@ -1907,7 +1909,7 @@
*/
private VerifyCredentialResponse verifyCredential(int userId, CredentialHash storedHash,
byte[] credential, @ChallengeType int challengeType, long challenge,
- ICheckCredentialProgressCallback progressCallback) throws RemoteException {
+ ICheckCredentialProgressCallback progressCallback) {
if ((storedHash == null || storedHash.hash.length == 0)
&& (credential == null || credential.length == 0)) {
// don't need to pass empty credentials to GateKeeper
@@ -1922,8 +1924,14 @@
// of unlocking the user, so yell if calling from the main thread.
StrictMode.noteDiskRead();
- GateKeeperResponse gateKeeperResponse = getGateKeeperService()
- .verifyChallenge(userId, challenge, storedHash.hash, credential);
+ GateKeeperResponse gateKeeperResponse;
+ try {
+ gateKeeperResponse = getGateKeeperService()
+ .verifyChallenge(userId, challenge, storedHash.hash, credential);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "gatekeeper verify failed", e);
+ gateKeeperResponse = GateKeeperResponse.ERROR;
+ }
VerifyCredentialResponse response = convertResponse(gateKeeperResponse);
boolean shouldReEnroll = gateKeeperResponse.getShouldReEnroll();
@@ -1932,7 +1940,11 @@
// credential has matched
if (progressCallback != null) {
- progressCallback.onCredentialVerified();
+ try {
+ progressCallback.onCredentialVerified();
+ } catch (RemoteException e) {
+ Log.w(TAG, "progressCallback throws exception", e);
+ }
}
notifyActivePasswordMetricsAvailable(storedHash.type, credential, userId);
unlockKeystore(credential, userId);
@@ -2007,7 +2019,7 @@
}
@Override
- public boolean checkVoldPassword(int userId) throws RemoteException {
+ public boolean checkVoldPassword(int userId) {
if (!mFirstCallToVold) {
return false;
}
@@ -2030,6 +2042,9 @@
try {
password = service.getPassword();
service.clearPassword();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "vold getPassword() failed", e);
+ return false;
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -2071,14 +2086,7 @@
final KeyStore ks = KeyStore.getInstance();
ks.onUserRemoved(userId);
- try {
- final IGateKeeperService gk = getGateKeeperService();
- if (gk != null) {
- gk.clearSecureUserId(userId);
- }
- } catch (RemoteException ex) {
- Slog.w(TAG, "unable to clear GK secure user id");
- }
+ gateKeeperClearSecureUserId(userId);
if (unknownUser || mUserManager.getUserInfo(userId).isManagedProfile()) {
removeKeystoreProfileKey(userId);
}
@@ -2141,8 +2149,7 @@
@Override
public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
- String[] args, ShellCallback callback, ResultReceiver resultReceiver)
- throws RemoteException {
+ String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
enforceShell();
final long origId = Binder.clearCallingIdentity();
try {
@@ -2304,15 +2311,18 @@
}
}
- protected synchronized IGateKeeperService getGateKeeperService()
- throws RemoteException {
+ protected synchronized IGateKeeperService getGateKeeperService() {
if (mGateKeeperService != null) {
return mGateKeeperService;
}
final IBinder service = ServiceManager.getService(Context.GATEKEEPER_SERVICE);
if (service != null) {
- service.linkToDeath(new GateKeeperDiedRecipient(), 0);
+ try {
+ service.linkToDeath(new GateKeeperDiedRecipient(), 0);
+ } catch (RemoteException e) {
+ Slog.w(TAG, " Unable to register death recipient", e);
+ }
mGateKeeperService = IGateKeeperService.Stub.asInterface(service);
return mGateKeeperService;
}
@@ -2321,6 +2331,14 @@
return null;
}
+ private void gateKeeperClearSecureUserId(int userId) {
+ try {
+ getGateKeeperService().clearSecureUserId(userId);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to clear SID", e);
+ }
+ }
+
/**
* A user's synthetic password does not change so it must be cached in certain circumstances to
* enable untrusted credential reset.
@@ -2330,7 +2348,7 @@
* credential.
*/
@GuardedBy("mSpManager")
- private SparseArray<AuthenticationToken> mSpCache = new SparseArray();
+ private SparseArray<AuthenticationToken> mSpCache = new SparseArray<>();
private void onAuthTokenKnownForUser(@UserIdInt int userId, AuthenticationToken auth) {
// Preemptively cache the SP and then try to remove it in a handler.
@@ -2435,8 +2453,7 @@
@GuardedBy("mSpManager")
@VisibleForTesting
protected AuthenticationToken initializeSyntheticPasswordLocked(byte[] credentialHash,
- byte[] credential, int credentialType, int requestedQuality,
- int userId) throws RemoteException {
+ byte[] credential, int credentialType, int requestedQuality, int userId) {
Slog.i(TAG, "Initialize SyntheticPassword for user: " + userId);
final AuthenticationToken auth = mSpManager.newSyntheticPasswordAndSid(
getGateKeeperService(), credentialHash, credential, userId);
@@ -2459,10 +2476,10 @@
} else {
clearUserKeyProtection(userId);
setKeystorePassword(null, userId);
- getGateKeeperService().clearSecureUserId(userId);
+ gateKeeperClearSecureUserId(userId);
}
fixateNewestUserKeyAuth(userId);
- setLong(SYNTHETIC_PASSWORD_HANDLE_KEY, handle, userId);
+ setSyntheticPasswordHandleLocked(handle, userId);
return auth;
}
@@ -2471,6 +2488,14 @@
SyntheticPasswordManager.DEFAULT_HANDLE, userId);
}
+ private void setSyntheticPasswordHandleLocked(long handle, int userId) {
+ final long oldHandle = getSyntheticPasswordHandleLocked(userId);
+ setLong(SYNTHETIC_PASSWORD_HANDLE_KEY, handle, userId);
+ setLong(PREV_SYNTHETIC_PASSWORD_HANDLE_KEY, oldHandle, userId);
+ setLong(SYNTHETIC_PASSWORD_UPDATE_TIME_KEY, System.currentTimeMillis(), userId);
+
+ }
+
private boolean isSyntheticPasswordBasedCredentialLocked(int userId) {
if (userId == USER_FRP) {
final int type = mStorage.readPersistentDataBlock().type;
@@ -2499,7 +2524,7 @@
private VerifyCredentialResponse spBasedDoVerifyCredential(byte[] userCredential,
@CredentialType int credentialType, @ChallengeType int challengeType, long challenge,
int userId, ICheckCredentialProgressCallback progressCallback,
- @Nullable ArrayList<PendingResetLockout> resetLockouts) throws RemoteException {
+ @Nullable ArrayList<PendingResetLockout> resetLockouts) {
final boolean hasEnrolledBiometrics = mInjector.hasEnrolledBiometrics(userId);
@@ -2606,7 +2631,7 @@
@GuardedBy("mSpManager")
private long setLockCredentialWithAuthTokenLocked(byte[] credential,
@CredentialType int credentialType, AuthenticationToken auth, int requestedQuality,
- int userId) throws RemoteException {
+ int userId) {
if (DEBUG) Slog.d(TAG, "setLockCredentialWithAuthTokenLocked: user=" + userId);
long newHandle = mSpManager.createPasswordBasedSyntheticPassword(getGateKeeperService(),
credential, credentialType, auth, requestedQuality, userId);
@@ -2638,7 +2663,7 @@
// we are clearing password of a secured device, so need to nuke SID as well.
mSpManager.clearSidForUser(userId);
- getGateKeeperService().clearSecureUserId(userId);
+ gateKeeperClearSecureUserId(userId);
// Clear key from vold so ActivityManager can just unlock the user with empty secret
// during boot. Vold storage needs to be unlocked before manipulation of the keys can
// succeed.
@@ -2648,7 +2673,7 @@
unlockKeystore(auth.deriveKeyStorePassword(), userId);
setKeystorePassword(null, userId);
}
- setLong(SYNTHETIC_PASSWORD_HANDLE_KEY, newHandle, userId);
+ setSyntheticPasswordHandleLocked(newHandle, userId);
synchronizeUnifiedWorkChallengeForProfiles(userId, profilePasswords);
notifyActivePasswordMetricsAvailable(credentialType, credential, userId);
@@ -2665,7 +2690,7 @@
@GuardedBy("mSpManager")
private void spBasedSetLockCredentialInternalLocked(byte[] credential, int credentialType,
byte[] savedCredential, int requestedQuality, int userId,
- boolean allowUntrustedChange, boolean isLockTiedToParent) throws RemoteException {
+ boolean allowUntrustedChange, boolean isLockTiedToParent) {
if (DEBUG) Slog.d(TAG, "spBasedSetLockCredentialInternalLocked: user=" + userId);
if (isManagedProfileWithUnifiedLock(userId)) {
// get credential from keystore when managed profile has unified lock
@@ -2688,9 +2713,8 @@
// If existing credential is provided, the existing credential must match.
if (savedCredential != null && auth == null) {
- throw new IllegalStateException("Failed to enroll "
- + (credentialType == CREDENTIAL_TYPE_PASSWORD
- ? "password" : "pattern"));
+ throw new IllegalStateException(String.format("Failed to enroll %s",
+ credentialType == CREDENTIAL_TYPE_PASSWORD ? "password" : "pattern"));
}
boolean untrustedReset = false;
if (auth != null) {
@@ -2741,7 +2765,7 @@
* If user is a managed profile with unified challenge, currentCredential is ignored.
*/
@Override
- public byte[] getHashFactor(byte[] currentCredential, int userId) throws RemoteException {
+ public byte[] getHashFactor(byte[] currentCredential, int userId) {
checkPasswordReadPermission(userId);
if (currentCredential == null || currentCredential.length == 0) {
currentCredential = null;
@@ -2770,8 +2794,7 @@
}
}
- private long addEscrowToken(byte[] token, int userId, EscrowTokenStateChangeCallback callback)
- throws RemoteException {
+ private long addEscrowToken(byte[] token, int userId, EscrowTokenStateChangeCallback callback) {
if (DEBUG) Slog.d(TAG, "addEscrowToken: user=" + userId);
synchronized (mSpManager) {
enableSyntheticPasswordLocked();
@@ -2847,7 +2870,7 @@
}
private boolean setLockCredentialWithToken(byte[] credential, int type, long tokenHandle,
- byte[] token, int requestedQuality, int userId) throws RemoteException {
+ byte[] token, int requestedQuality, int userId) {
boolean result;
synchronized (mSpManager) {
if (!mSpManager.hasEscrowData(userId)) {
@@ -2874,8 +2897,7 @@
@GuardedBy("mSpManager")
private boolean setLockCredentialWithTokenInternalLocked(byte[] credential, int type,
- long tokenHandle, byte[] token, int requestedQuality, int userId)
- throws RemoteException {
+ long tokenHandle, byte[] token, int requestedQuality, int userId) {
final AuthenticationResult result;
result = mSpManager.unwrapTokenBasedSyntheticPassword(
getGateKeeperService(), tokenHandle, token, userId);
@@ -2901,8 +2923,7 @@
return true;
}
- private boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId)
- throws RemoteException {
+ private boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId) {
AuthenticationResult authResult;
synchronized (mSpManager) {
if (!mSpManager.hasEscrowData(userId)) {
@@ -2920,29 +2941,57 @@
return true;
}
+ static String timestampToString(long timestamp) {
+ return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(timestamp));
+ }
+
@Override
- protected void dump(FileDescriptor fd, PrintWriter pw, String[] args){
- if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+ protected void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) {
+ if (!DumpUtils.checkDumpPermission(mContext, TAG, printWriter)) return;
+ IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " ");
pw.println("Current lock settings service state:");
+
pw.println(String.format("SP Enabled = %b",
mLockPatternUtils.isSyntheticPasswordEnabled()));
+ pw.println();
+ pw.println("User State:");
+ pw.increaseIndent();
List<UserInfo> users = mUserManager.getUsers();
for (int user = 0; user < users.size(); user++) {
final int userId = users.get(user).id;
- pw.println(" User " + userId);
+ pw.println("User " + userId);
+ pw.increaseIndent();
synchronized (mSpManager) {
- pw.println(String.format(" SP Handle = %x",
+ pw.println(String.format("SP Handle: %x",
getSyntheticPasswordHandleLocked(userId)));
+ pw.println(String.format("Last changed: %s (%x)",
+ timestampToString(getLong(SYNTHETIC_PASSWORD_UPDATE_TIME_KEY, 0, userId)),
+ getLong(PREV_SYNTHETIC_PASSWORD_HANDLE_KEY, 0, userId)));
}
try {
- pw.println(String.format(" SID = %x",
+ pw.println(String.format("SID: %x",
getGateKeeperService().getSecureUserId(userId)));
} catch (RemoteException e) {
// ignore.
}
+ // It's OK to dump the password type since anyone with physical access can just
+ // observe it from the keyguard directly.
+ pw.println("PasswordType: " + getLong(LockPatternUtils.PASSWORD_TYPE_KEY, 0, userId));
+ pw.println("hasPassword: " + havePassword(userId));
+ pw.println("hasPattern: " + havePattern(userId)); // print raw credential type instead?
+ pw.println("SeparateChallenge: " + getSeparateProfileChallengeEnabled(userId));
+ pw.decreaseIndent();
}
+ pw.println();
+ pw.decreaseIndent();
+
+ pw.println("Storage:");
+ pw.increaseIndent();
+ mStorage.dump(pw);
+ pw.println();
+ pw.decreaseIndent();
}
private void disableEscrowTokenOnNonManagedDevicesIfNeeded(int userId) {
@@ -3081,11 +3130,7 @@
@Override
public long addEscrowToken(byte[] token, int userId,
EscrowTokenStateChangeCallback callback) {
- try {
- return LockSettingsService.this.addEscrowToken(token, userId, callback);
- } catch (RemoteException re) {
- throw re.rethrowFromSystemServer();
- }
+ return LockSettingsService.this.addEscrowToken(token, userId, callback);
}
@Override
@@ -3105,21 +3150,13 @@
throw new UnsupportedOperationException(
"This operation requires secure lock screen feature.");
}
- try {
- return LockSettingsService.this.setLockCredentialWithToken(credential, type,
- tokenHandle, token, requestedQuality, userId);
- } catch (RemoteException re) {
- throw re.rethrowFromSystemServer();
- }
+ return LockSettingsService.this.setLockCredentialWithToken(credential, type,
+ tokenHandle, token, requestedQuality, userId);
}
@Override
public boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId) {
- try {
- return LockSettingsService.this.unlockUserWithToken(tokenHandle, token, userId);
- } catch (RemoteException re) {
- throw re.rethrowFromSystemServer();
- }
+ return LockSettingsService.this.unlockUserWithToken(tokenHandle, token, userId);
}
}
}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
index 29b8aa2..fe12a94 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
@@ -35,6 +35,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockPatternUtils.CredentialType;
@@ -140,7 +141,7 @@
dos.close();
return os.toByteArray();
} catch (IOException e) {
- throw new RuntimeException(e);
+ throw new IllegalStateException("Fail to serialze credential hash", e);
}
}
@@ -157,7 +158,7 @@
}
return new CredentialHash(hash, type);
} catch (IOException e) {
- throw new RuntimeException(e);
+ throw new IllegalStateException("Fail to deserialze credential hash", e);
}
}
}
@@ -666,7 +667,7 @@
dos.writeInt(qualityForUi);
dos.write(payload);
} catch (IOException e) {
- throw new RuntimeException("ByteArrayOutputStream cannot throw IOException");
+ throw new IllegalStateException("ByteArrayOutputStream cannot throw IOException");
}
return os.toByteArray();
}
@@ -676,6 +677,26 @@
void initialize(SQLiteDatabase db);
}
+ public void dump(IndentingPrintWriter pw) {
+ final UserManager um = UserManager.get(mContext);
+ for (UserInfo user : um.getUsers(false)) {
+ File userPath = getSyntheticPasswordDirectoryForUser(user.id);
+ pw.println(String.format("User %d [%s]:", user.id, userPath.getAbsolutePath()));
+ pw.increaseIndent();
+ File[] files = userPath.listFiles();
+ if (files != null) {
+ for (File file : files) {
+ pw.println(String.format("%4d %s %s", file.length(),
+ LockSettingsService.timestampToString(file.lastModified()),
+ file.getName()));
+ }
+ } else {
+ pw.println("[Not found]");
+ }
+ pw.decreaseIndent();
+ }
+ }
+
static class DatabaseHelper extends SQLiteOpenHelper {
private static final String TAG = "LockSettingsDB";
private static final String DATABASE_NAME = "locksettings.db";
diff --git a/services/core/java/com/android/server/locksettings/PasswordSlotManager.java b/services/core/java/com/android/server/locksettings/PasswordSlotManager.java
index 4ef63c0..17aca15 100644
--- a/services/core/java/com/android/server/locksettings/PasswordSlotManager.java
+++ b/services/core/java/com/android/server/locksettings/PasswordSlotManager.java
@@ -109,7 +109,7 @@
public void markSlotInUse(int slot) throws RuntimeException {
ensureSlotMapLoaded();
if (mSlotMap.containsKey(slot) && !mSlotMap.get(slot).equals(getMode())) {
- throw new RuntimeException("password slot " + slot + " is not available");
+ throw new IllegalStateException("password slot " + slot + " is not available");
}
mSlotMap.put(slot, getMode());
saveSlotMap();
@@ -123,7 +123,7 @@
public void markSlotDeleted(int slot) throws RuntimeException {
ensureSlotMapLoaded();
if (mSlotMap.containsKey(slot) && !mSlotMap.get(slot).equals(getMode())) {
- throw new RuntimeException("password slot " + slot + " cannot be deleted");
+ throw new IllegalStateException("password slot " + slot + " cannot be deleted");
}
mSlotMap.remove(slot);
saveSlotMap();
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java
index 388e51f..ea0fb47 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java
@@ -18,6 +18,7 @@
import android.security.keystore.KeyProperties;
import android.security.keystore.KeyProtection;
+import android.util.Slog;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -43,6 +44,7 @@
import javax.crypto.spec.SecretKeySpec;
public class SyntheticPasswordCrypto {
+ private static final String TAG = "SyntheticPasswordCrypto";
private static final int PROFILE_KEY_IV_SIZE = 12;
private static final int DEFAULT_TAG_LENGTH_BITS = 128;
private static final int AES_KEY_LENGTH = 32; // 256-bit AES key
@@ -80,12 +82,12 @@
byte[] ciphertext = cipher.doFinal(blob);
byte[] iv = cipher.getIV();
if (iv.length != PROFILE_KEY_IV_SIZE) {
- throw new RuntimeException("Invalid iv length: " + iv.length);
+ throw new IllegalArgumentException("Invalid iv length: " + iv.length);
}
final GCMParameterSpec spec = cipher.getParameters().getParameterSpec(
GCMParameterSpec.class);
if (spec.getTLen() != DEFAULT_TAG_LENGTH_BITS) {
- throw new RuntimeException("Invalid tag length: " + spec.getTLen());
+ throw new IllegalArgumentException("Invalid tag length: " + spec.getTLen());
}
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
outputStream.write(iv);
@@ -102,7 +104,7 @@
} catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException
| IllegalBlockSizeException | BadPaddingException | IOException
| InvalidParameterSpecException e) {
- e.printStackTrace();
+ Slog.e(TAG, "Failed to encrypt", e);
return null;
}
}
@@ -116,7 +118,7 @@
} catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException
| IllegalBlockSizeException | BadPaddingException
| InvalidAlgorithmParameterException e) {
- e.printStackTrace();
+ Slog.e(TAG, "Failed to decrypt", e);
return null;
}
}
@@ -130,8 +132,8 @@
byte[] intermediate = decrypt(applicationId, APPLICATION_ID_PERSONALIZATION, blob);
return decrypt(decryptionKey, intermediate);
} catch (Exception e) {
- e.printStackTrace();
- throw new RuntimeException("Failed to decrypt blob", e);
+ Slog.e(TAG, "Failed to decrypt V1 blob", e);
+ throw new IllegalStateException("Failed to decrypt blob", e);
}
}
@@ -148,8 +150,8 @@
| KeyStoreException | NoSuchPaddingException | NoSuchAlgorithmException
| InvalidKeyException | UnrecoverableKeyException
| InvalidAlgorithmParameterException e) {
- e.printStackTrace();
- throw new RuntimeException("Failed to decrypt blob", e);
+ Slog.e(TAG, "Failed to decrypt blob", e);
+ throw new IllegalStateException("Failed to decrypt blob", e);
}
}
@@ -180,8 +182,8 @@
| KeyStoreException | NoSuchPaddingException | NoSuchAlgorithmException
| InvalidKeyException
| InvalidParameterSpecException e) {
- e.printStackTrace();
- throw new RuntimeException("Failed to encrypt blob", e);
+ Slog.e(TAG, "Failed to create blob", e);
+ throw new IllegalStateException("Failed to encrypt blob", e);
}
}
@@ -193,7 +195,7 @@
keyStore.deleteEntry(keyAlias);
} catch (KeyStoreException | NoSuchAlgorithmException | CertificateException
| IOException e) {
- e.printStackTrace();
+ Slog.e(TAG, "Failed to destroy blob", e);
}
}
@@ -202,7 +204,7 @@
final int PADDING_LENGTH = 128;
MessageDigest digest = MessageDigest.getInstance("SHA-512");
if (personalisation.length > PADDING_LENGTH) {
- throw new RuntimeException("Personalisation too long");
+ throw new IllegalArgumentException("Personalisation too long");
}
// Personalize the hash
// Pad it to the block size of the hash function
@@ -213,7 +215,7 @@
}
return digest.digest();
} catch (NoSuchAlgorithmException e) {
- throw new RuntimeException("NoSuchAlgorithmException for SHA-512", e);
+ throw new IllegalStateException("NoSuchAlgorithmException for SHA-512", e);
}
}
}
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
index 1ba0e8c..955a9aa 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
@@ -349,25 +349,28 @@
* a default all-zero key is used. If the value is not specified, a fresh random secret is
* generated as the value.
*
- * @return the value stored in the weaver slot
- * @throws RemoteException
+ * @return the value stored in the weaver slot, or null if the operation fails
*/
- private byte[] weaverEnroll(int slot, byte[] key, @Nullable byte[] value)
- throws RemoteException {
+ private byte[] weaverEnroll(int slot, byte[] key, @Nullable byte[] value) {
if (slot == INVALID_WEAVER_SLOT || slot >= mWeaverConfig.slots) {
- throw new RuntimeException("Invalid slot for weaver");
+ throw new IllegalArgumentException("Invalid slot for weaver");
}
if (key == null) {
key = new byte[mWeaverConfig.keySize];
} else if (key.length != mWeaverConfig.keySize) {
- throw new RuntimeException("Invalid key size for weaver");
+ throw new IllegalArgumentException("Invalid key size for weaver");
}
if (value == null) {
value = secureRandom(mWeaverConfig.valueSize);
}
- int writeStatus = mWeaver.write(slot, toByteArrayList(key), toByteArrayList(value));
- if (writeStatus != WeaverStatus.OK) {
- Log.e(TAG, "weaver write failed, slot: " + slot + " status: " + writeStatus);
+ try {
+ int writeStatus = mWeaver.write(slot, toByteArrayList(key), toByteArrayList(value));
+ if (writeStatus != WeaverStatus.OK) {
+ Log.e(TAG, "weaver write failed, slot: " + slot + " status: " + writeStatus);
+ return null;
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "weaver write failed", e);
return null;
}
return value;
@@ -377,47 +380,53 @@
* Verify the supplied key against a weaver slot, returning a response indicating whether
* the verification is successful, throttled or failed. If successful, the bound secret
* is also returned.
- * @throws RemoteException
*/
- private VerifyCredentialResponse weaverVerify(int slot, byte[] key) throws RemoteException {
+ private VerifyCredentialResponse weaverVerify(int slot, byte[] key) {
if (slot == INVALID_WEAVER_SLOT || slot >= mWeaverConfig.slots) {
- throw new RuntimeException("Invalid slot for weaver");
+ throw new IllegalArgumentException("Invalid slot for weaver");
}
if (key == null) {
key = new byte[mWeaverConfig.keySize];
} else if (key.length != mWeaverConfig.keySize) {
- throw new RuntimeException("Invalid key size for weaver");
+ throw new IllegalArgumentException("Invalid key size for weaver");
}
final VerifyCredentialResponse[] response = new VerifyCredentialResponse[1];
- mWeaver.read(slot, toByteArrayList(key), (int status, WeaverReadResponse readResponse) -> {
- switch (status) {
- case WeaverReadStatus.OK:
- response[0] = new VerifyCredentialResponse(
- fromByteArrayList(readResponse.value));
- break;
- case WeaverReadStatus.THROTTLE:
- response[0] = new VerifyCredentialResponse(readResponse.timeout);
- Log.e(TAG, "weaver read failed (THROTTLE), slot: " + slot);
- break;
- case WeaverReadStatus.INCORRECT_KEY:
- if (readResponse.timeout == 0) {
- response[0] = VerifyCredentialResponse.ERROR;
- Log.e(TAG, "weaver read failed (INCORRECT_KEY), slot: " + slot);
- } else {
- response[0] = new VerifyCredentialResponse(readResponse.timeout);
- Log.e(TAG, "weaver read failed (INCORRECT_KEY/THROTTLE), slot: " + slot);
+ try {
+ mWeaver.read(slot, toByteArrayList(key),
+ (int status, WeaverReadResponse readResponse) -> {
+ switch (status) {
+ case WeaverReadStatus.OK:
+ response[0] = new VerifyCredentialResponse(
+ fromByteArrayList(readResponse.value));
+ break;
+ case WeaverReadStatus.THROTTLE:
+ response[0] = new VerifyCredentialResponse(readResponse.timeout);
+ Log.e(TAG, "weaver read failed (THROTTLE), slot: " + slot);
+ break;
+ case WeaverReadStatus.INCORRECT_KEY:
+ if (readResponse.timeout == 0) {
+ response[0] = VerifyCredentialResponse.ERROR;
+ Log.e(TAG, "weaver read failed (INCORRECT_KEY), slot: " + slot);
+ } else {
+ response[0] = new VerifyCredentialResponse(readResponse.timeout);
+ Log.e(TAG, "weaver read failed (INCORRECT_KEY/THROTTLE), slot: "
+ + slot);
+ }
+ break;
+ case WeaverReadStatus.FAILED:
+ response[0] = VerifyCredentialResponse.ERROR;
+ Log.e(TAG, "weaver read failed (FAILED), slot: " + slot);
+ break;
+ default:
+ response[0] = VerifyCredentialResponse.ERROR;
+ Log.e(TAG, "weaver read unknown status " + status + ", slot: " + slot);
+ break;
}
- break;
- case WeaverReadStatus.FAILED:
- response[0] = VerifyCredentialResponse.ERROR;
- Log.e(TAG, "weaver read failed (FAILED), slot: " + slot);
- break;
- default:
- response[0] = VerifyCredentialResponse.ERROR;
- Log.e(TAG, "weaver read unknown status " + status + ", slot: " + slot);
- break;
- }
- });
+ });
+ } catch (RemoteException e) {
+ response[0] = VerifyCredentialResponse.ERROR;
+ Log.e(TAG, "weaver read failed, slot: " + slot, e);
+ }
return response[0];
}
@@ -460,12 +469,15 @@
*
*/
public AuthenticationToken newSyntheticPasswordAndSid(IGateKeeperService gatekeeper,
- byte[] hash, byte[] credential, int userId) throws RemoteException {
+ byte[] hash, byte[] credential, int userId) {
AuthenticationToken result = AuthenticationToken.create();
GateKeeperResponse response;
if (hash != null) {
- response = gatekeeper.enroll(userId, hash, credential,
- result.deriveGkPassword());
+ try {
+ response = gatekeeper.enroll(userId, hash, credential, result.deriveGkPassword());
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Failed to enroll credential duing SP init", e);
+ }
if (response.getResponseCode() != GateKeeperResponse.RESPONSE_OK) {
Log.w(TAG, "Fail to migrate SID, assuming no SID, user " + userId);
clearSidForUser(userId);
@@ -484,9 +496,13 @@
* Used when adding password to previously-unsecured devices.
*/
public void newSidForUser(IGateKeeperService gatekeeper, AuthenticationToken authToken,
- int userId) throws RemoteException {
- GateKeeperResponse response = gatekeeper.enroll(userId, null, null,
- authToken.deriveGkPassword());
+ int userId) {
+ GateKeeperResponse response;
+ try {
+ response = gatekeeper.enroll(userId, null, null, authToken.deriveGkPassword());
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Failed to create new SID for user", e);
+ }
if (response.getResponseCode() != GateKeeperResponse.RESPONSE_OK) {
Log.e(TAG, "Fail to create new SID for user " + userId);
return;
@@ -565,12 +581,8 @@
Set<Integer> usedSlots = getUsedWeaverSlots();
if (!usedSlots.contains(slot)) {
Log.i(TAG, "Destroy weaver slot " + slot + " for user " + userId);
- try {
- weaverEnroll(slot, null, null);
- mPasswordSlotManager.markSlotDeleted(slot);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to destroy slot", e);
- }
+ weaverEnroll(slot, null, null);
+ mPasswordSlotManager.markSlotDeleted(slot);
} else {
Log.w(TAG, "Skip destroying reused weaver slot " + slot + " for user " + userId);
}
@@ -608,7 +620,7 @@
return i;
}
}
- throw new RuntimeException("Run out of weaver slots.");
+ throw new IllegalStateException("Run out of weaver slots.");
}
/**
@@ -622,11 +634,12 @@
*
* @see #newSidForUser
* @see #clearSidForUser
+ * @return a new password handle for the wrapped SP blob
+ * @throw IllegalStateException if creation fails.
*/
public long createPasswordBasedSyntheticPassword(IGateKeeperService gatekeeper,
byte[] credential, int credentialType, AuthenticationToken authToken,
- int requestedQuality, int userId)
- throws RemoteException {
+ int requestedQuality, int userId) {
if (credential == null || credentialType == LockPatternUtils.CREDENTIAL_TYPE_NONE) {
credentialType = LockPatternUtils.CREDENTIAL_TYPE_NONE;
credential = DEFAULT_PASSWORD;
@@ -642,10 +655,11 @@
// Weaver based user password
int weaverSlot = getNextAvailableWeaverSlot();
Log.i(TAG, "Weaver enroll password to slot " + weaverSlot + " for user " + userId);
- byte[] weaverSecret = weaverEnroll(weaverSlot, passwordTokenToWeaverKey(pwdToken), null);
+ byte[] weaverSecret = weaverEnroll(weaverSlot, passwordTokenToWeaverKey(pwdToken),
+ null);
if (weaverSecret == null) {
- Log.e(TAG, "Fail to enroll user password under weaver " + userId);
- return DEFAULT_HANDLE;
+ throw new IllegalStateException(
+ "Fail to enroll user password under weaver " + userId);
}
saveWeaverSlot(weaverSlot, handle, userId);
mPasswordSlotManager.markSlotInUse(weaverSlot);
@@ -657,13 +671,22 @@
} else {
// In case GK enrollment leaves persistent state around (in RPMB), this will nuke them
// to prevent them from accumulating and causing problems.
- gatekeeper.clearSecureUserId(fakeUid(userId));
+ try {
+ gatekeeper.clearSecureUserId(fakeUid(userId));
+ } catch (RemoteException ignore) {
+ Log.w(TAG, "Failed to clear SID from gatekeeper");
+ }
// GateKeeper based user password
- GateKeeperResponse response = gatekeeper.enroll(fakeUid(userId), null, null,
- passwordTokenToGkInput(pwdToken));
+ GateKeeperResponse response;
+ try {
+ response = gatekeeper.enroll(fakeUid(userId), null, null,
+ passwordTokenToGkInput(pwdToken));
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Failed to enroll password for new SP blob", e);
+ }
if (response.getResponseCode() != GateKeeperResponse.RESPONSE_OK) {
- Log.e(TAG, "Fail to enroll user password when creating SP for user " + userId);
- return DEFAULT_HANDLE;
+ throw new IllegalStateException(
+ "Fail to enroll user password when creating SP for user " + userId);
}
pwd.passwordHandle = response.getPayload();
sid = sidFromPasswordHandle(pwd.passwordHandle);
@@ -680,14 +703,20 @@
public VerifyCredentialResponse verifyFrpCredential(IGateKeeperService gatekeeper,
byte[] userCredential, int credentialType,
- ICheckCredentialProgressCallback progressCallback) throws RemoteException {
+ ICheckCredentialProgressCallback progressCallback) {
PersistentData persistentData = mStorage.readPersistentDataBlock();
if (persistentData.type == PersistentData.TYPE_SP) {
PasswordData pwd = PasswordData.fromBytes(persistentData.payload);
byte[] pwdToken = computePasswordToken(userCredential, pwd);
- GateKeeperResponse response = gatekeeper.verifyChallenge(fakeUid(persistentData.userId),
- 0 /* challenge */, pwd.passwordHandle, passwordTokenToGkInput(pwdToken));
+ GateKeeperResponse response;
+ try {
+ response = gatekeeper.verifyChallenge(fakeUid(persistentData.userId),
+ 0 /* challenge */, pwd.passwordHandle, passwordTokenToGkInput(pwdToken));
+ } catch (RemoteException e) {
+ Log.e(TAG, "FRP verifyChallenge failed", e);
+ return VerifyCredentialResponse.ERROR;
+ }
return VerifyCredentialResponse.fromGateKeeperResponse(response);
} else if (persistentData.type == PersistentData.TYPE_SP_WEAVER) {
PasswordData pwd = PasswordData.fromBytes(persistentData.payload);
@@ -805,11 +834,9 @@
}
if (isWeaverAvailable()) {
int slot = getNextAvailableWeaverSlot();
- try {
- Log.i(TAG, "Weaver enroll token to slot " + slot + " for user " + userId);
- weaverEnroll(slot, null, tokenData.weaverSecret);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to enroll weaver secret when activating token", e);
+ Log.i(TAG, "Weaver enroll token to slot " + slot + " for user " + userId);
+ if (weaverEnroll(slot, null, tokenData.weaverSecret) == null) {
+ Log.e(TAG, "Failed to enroll weaver secret when activating token");
return false;
}
saveWeaverSlot(slot, handle, userId);
@@ -859,7 +886,7 @@
*/
public AuthenticationResult unwrapPasswordBasedSyntheticPassword(IGateKeeperService gatekeeper,
long handle, byte[] credential, int userId,
- ICheckCredentialProgressCallback progressCallback) throws RemoteException {
+ ICheckCredentialProgressCallback progressCallback) {
if (credential == null) {
credential = DEFAULT_PASSWORD;
}
@@ -886,14 +913,28 @@
applicationId = transformUnderWeaverSecret(pwdToken, result.gkResponse.getPayload());
} else {
byte[] gkPwdToken = passwordTokenToGkInput(pwdToken);
- GateKeeperResponse response = gatekeeper.verifyChallenge(fakeUid(userId), 0L,
- pwd.passwordHandle, gkPwdToken);
+ GateKeeperResponse response;
+ try {
+ response = gatekeeper.verifyChallenge(fakeUid(userId), 0L,
+ pwd.passwordHandle, gkPwdToken);
+ } catch (RemoteException e) {
+ Log.e(TAG, "gatekeeper verify failed", e);
+ result.gkResponse = VerifyCredentialResponse.ERROR;
+ return result;
+ }
int responseCode = response.getResponseCode();
if (responseCode == GateKeeperResponse.RESPONSE_OK) {
result.gkResponse = VerifyCredentialResponse.OK;
if (response.getShouldReEnroll()) {
- GateKeeperResponse reenrollResponse = gatekeeper.enroll(fakeUid(userId),
- pwd.passwordHandle, gkPwdToken, gkPwdToken);
+ GateKeeperResponse reenrollResponse;
+ try {
+ reenrollResponse = gatekeeper.enroll(fakeUid(userId),
+ pwd.passwordHandle, gkPwdToken, gkPwdToken);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Fail to invoke gatekeeper.enroll", e);
+ reenrollResponse = GateKeeperResponse.ERROR;
+ // continue the flow anyway
+ }
if (reenrollResponse.getResponseCode() == GateKeeperResponse.RESPONSE_OK) {
pwd.passwordHandle = reenrollResponse.getPayload();
saveState(PASSWORD_DATA_NAME, pwd.toBytes(), handle, userId);
@@ -922,7 +963,11 @@
// Supplied credential passes first stage weaver/gatekeeper check so it should be correct.
// Notify the callback so the keyguard UI can proceed immediately.
if (progressCallback != null) {
- progressCallback.onCredentialVerified();
+ try {
+ progressCallback.onCredentialVerified();
+ } catch (RemoteException e) {
+ Log.w(TAG, "progressCallback throws exception", e);
+ }
}
result.authToken = unwrapSyntheticPasswordBlob(handle, SYNTHETIC_PASSWORD_PASSWORD_BASED,
applicationId, sid, userId);
@@ -938,8 +983,7 @@
* verification to referesh the SID & Auth token maintained by the system.
*/
public @NonNull AuthenticationResult unwrapTokenBasedSyntheticPassword(
- IGateKeeperService gatekeeper, long handle, byte[] token, int userId)
- throws RemoteException {
+ IGateKeeperService gatekeeper, long handle, byte[] token, int userId) {
AuthenticationResult result = new AuthenticationResult();
byte[] secdiscardable = loadSecdiscardable(handle, userId);
int slotId = loadWeaverSlot(handle, userId);
@@ -985,10 +1029,10 @@
if (version != SYNTHETIC_PASSWORD_VERSION_V3
&& version != SYNTHETIC_PASSWORD_VERSION_V2
&& version != SYNTHETIC_PASSWORD_VERSION_V1) {
- throw new RuntimeException("Unknown blob version");
+ throw new IllegalArgumentException("Unknown blob version");
}
if (blob[1] != type) {
- throw new RuntimeException("Invalid blob type");
+ throw new IllegalArgumentException("Invalid blob type");
}
final byte[] secret;
if (version == SYNTHETIC_PASSWORD_VERSION_V1) {
@@ -1028,38 +1072,48 @@
* decrypt SP.
*/
public @Nullable VerifyCredentialResponse verifyChallenge(IGateKeeperService gatekeeper,
- @NonNull AuthenticationToken auth, long challenge, int userId) throws RemoteException {
+ @NonNull AuthenticationToken auth, long challenge, int userId) {
byte[] spHandle = loadSyntheticPasswordHandle(userId);
if (spHandle == null) {
// There is no password handle associated with the given user, i.e. the user is not
// secured by lockscreen and has no SID, so just return here;
return null;
}
- VerifyCredentialResponse result;
- GateKeeperResponse response = gatekeeper.verifyChallenge(userId, challenge,
- spHandle, auth.deriveGkPassword());
+ GateKeeperResponse response;
+ try {
+ response = gatekeeper.verifyChallenge(userId, challenge,
+ spHandle, auth.deriveGkPassword());
+ } catch (RemoteException e) {
+ Log.e(TAG, "Fail to verify with gatekeeper " + userId, e);
+ return VerifyCredentialResponse.ERROR;
+ }
int responseCode = response.getResponseCode();
if (responseCode == GateKeeperResponse.RESPONSE_OK) {
- result = new VerifyCredentialResponse(response.getPayload());
+ VerifyCredentialResponse result = new VerifyCredentialResponse(response.getPayload());
if (response.getShouldReEnroll()) {
- response = gatekeeper.enroll(userId, spHandle,
- spHandle, auth.deriveGkPassword());
+ try {
+ response = gatekeeper.enroll(userId, spHandle, spHandle,
+ auth.deriveGkPassword());
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to invoke gatekeeper.enroll", e);
+ response = GateKeeperResponse.ERROR;
+ }
if (response.getResponseCode() == GateKeeperResponse.RESPONSE_OK) {
spHandle = response.getPayload();
saveSyntheticPasswordHandle(spHandle, userId);
// Call self again to re-verify with updated handle
return verifyChallenge(gatekeeper, auth, challenge, userId);
} else {
+ // Fall through, return result from the previous verification attempt.
Log.w(TAG, "Fail to re-enroll SP handle for user " + userId);
- // Fall through, return existing handle
}
}
+ return result;
} else if (responseCode == GateKeeperResponse.RESPONSE_RETRY) {
- result = new VerifyCredentialResponse(response.getTimeout());
+ return new VerifyCredentialResponse(response.getTimeout());
} else {
- result = VerifyCredentialResponse.ERROR;
+ return VerifyCredentialResponse.ERROR;
}
- return result;
}
public boolean existsHandle(long handle, int userId) {
@@ -1183,7 +1237,7 @@
private byte[] passwordTokenToWeaverKey(byte[] token) {
byte[] key = SyntheticPasswordCrypto.personalisedHash(PERSONALISATION_WEAVER_KEY, token);
if (key.length < mWeaverConfig.keySize) {
- throw new RuntimeException("weaver key length too small");
+ throw new IllegalArgumentException("weaver key length too small");
}
return Arrays.copyOf(key, mWeaverConfig.keySize);
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 6fe924e..e90db38 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -231,7 +231,7 @@
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.internal.util.function.TriPredicate;
-import com.android.server.DeviceIdleController;
+import com.android.server.DeviceIdleInternal;
import com.android.server.EventLogTags;
import com.android.server.IoThread;
import com.android.server.LocalServices;
@@ -621,6 +621,8 @@
mConditionProviders.readXml(
parser, mAllowedManagedServicePackages, forRestore, userId);
migratedManagedServices = true;
+ } else if (mSnoozeHelper.XML_TAG_NAME.equals(parser.getName())) {
+ mSnoozeHelper.readXml(parser);
}
if (LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG.equals(parser.getName())) {
if (forRestore && userId != UserHandle.USER_SYSTEM) {
@@ -709,6 +711,7 @@
mPreferencesHelper.writeXml(out, forBackup, userId);
mListeners.writeXml(out, forBackup, userId);
mAssistants.writeXml(out, forBackup, userId);
+ mSnoozeHelper.writeXml(out);
mConditionProviders.writeXml(out, forBackup, userId);
if (!forBackup || userId == UserHandle.USER_SYSTEM) {
writeSecureNotificationsPolicy(out);
@@ -1753,6 +1756,7 @@
com.android.internal.R.integer.config_notificationWarnRemoteViewSizeBytes);
mStripRemoteViewsSizeBytes = getContext().getResources().getInteger(
com.android.internal.R.integer.config_notificationStripRemoteViewSizeBytes);
+
}
@Override
@@ -4830,7 +4834,7 @@
final ActivityManagerInternal am = LocalServices
.getService(ActivityManagerInternal.class);
final long duration = LocalServices.getService(
- DeviceIdleController.LocalService.class).getNotificationWhitelistDuration();
+ DeviceIdleInternal.class).getNotificationWhitelistDuration();
for (int i = 0; i < intentCount; i++) {
PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
if (pendingIntent != null) {
@@ -5284,7 +5288,7 @@
updateLightsLocked();
if (mSnoozeCriterionId != null) {
mAssistants.notifyAssistantSnoozedLocked(r.sbn, mSnoozeCriterionId);
- mSnoozeHelper.snooze(r);
+ mSnoozeHelper.snooze(r, mSnoozeCriterionId);
} else {
mSnoozeHelper.snooze(r, mDuration);
}
@@ -5387,6 +5391,27 @@
@Override
public void run() {
synchronized (mNotificationLock) {
+ final Long snoozeAt =
+ mSnoozeHelper.getSnoozeTimeForUnpostedNotification(
+ r.getUser().getIdentifier(),
+ r.sbn.getPackageName(), r.sbn.getKey());
+ final long currentTime = System.currentTimeMillis();
+ if (snoozeAt.longValue() > currentTime) {
+ (new SnoozeNotificationRunnable(r.sbn.getKey(),
+ snoozeAt.longValue() - currentTime, null)).snoozeLocked(r);
+ return;
+ }
+
+ final String contextId =
+ mSnoozeHelper.getSnoozeContextForUnpostedNotification(
+ r.getUser().getIdentifier(),
+ r.sbn.getPackageName(), r.sbn.getKey());
+ if (contextId != null) {
+ (new SnoozeNotificationRunnable(r.sbn.getKey(),
+ 0, contextId)).snoozeLocked(r);
+ return;
+ }
+
mEnqueuedNotifications.add(r);
scheduleTimeoutLocked(r);
@@ -6937,6 +6962,7 @@
if (DBG) {
Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName));
}
+ mSnoozeHelper.cleanupPersistedContext(key);
mSnoozeHelper.repost(key);
handleSavePolicyFile();
}
diff --git a/services/core/java/com/android/server/notification/SnoozeHelper.java b/services/core/java/com/android/server/notification/SnoozeHelper.java
index 91f497c..8125d0d 100644
--- a/services/core/java/com/android/server/notification/SnoozeHelper.java
+++ b/services/core/java/com/android/server/notification/SnoozeHelper.java
@@ -55,6 +55,21 @@
* NotificationManagerService helper for handling snoozed notifications.
*/
public class SnoozeHelper {
+ public static final String XML_SNOOZED_NOTIFICATION_VERSION = "1";
+
+ protected static final String XML_TAG_NAME = "snoozed-notifications";
+
+ private static final String XML_SNOOZED_NOTIFICATION = "notification";
+ private static final String XML_SNOOZED_NOTIFICATION_CONTEXT = "context";
+ private static final String XML_SNOOZED_NOTIFICATION_PKG = "pkg";
+ private static final String XML_SNOOZED_NOTIFICATION_USER_ID = "user-id";
+ private static final String XML_SNOOZED_NOTIFICATION_KEY = "key";
+ //the time the snoozed notification should be reposted
+ private static final String XML_SNOOZED_NOTIFICATION_TIME = "time";
+ private static final String XML_SNOOZED_NOTIFICATION_CONTEXT_ID = "id";
+ private static final String XML_SNOOZED_NOTIFICATION_VERSION_LABEL = "version";
+
+
private static final String TAG = "SnoozeHelper";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final String INDENT = " ";
@@ -72,6 +87,17 @@
// User id : package name : notification key : record.
private ArrayMap<Integer, ArrayMap<String, ArrayMap<String, NotificationRecord>>>
mSnoozedNotifications = new ArrayMap<>();
+ // User id : package name : notification key : time-milliseconds .
+ // This member stores persisted snoozed notification trigger times. it persists through reboots
+ // It should have the notifications that haven't expired or re-posted yet
+ private ArrayMap<Integer, ArrayMap<String, ArrayMap<String, Long>>>
+ mPersistedSnoozedNotifications = new ArrayMap<>();
+ // User id : package name : notification key : creation ID .
+ // This member stores persisted snoozed notification trigger context for the assistant
+ // it persists through reboots.
+ // It should have the notifications that haven't expired or re-posted yet
+ private ArrayMap<Integer, ArrayMap<String, ArrayMap<String, String>>>
+ mPersistedSnoozedNotificationsWithContext = new ArrayMap<>();
// notification key : package.
private ArrayMap<String, String> mPackages = new ArrayMap<>();
// key : userId
@@ -89,6 +115,34 @@
mUserProfiles = userProfiles;
}
+ void cleanupPersistedContext(String key){
+ int userId = mUsers.get(key);
+ String pkg = mPackages.get(key);
+ synchronized (mPersistedSnoozedNotificationsWithContext) {
+ removeRecord(pkg, key, userId, mPersistedSnoozedNotificationsWithContext);
+ }
+ }
+
+ //This function has a side effect of removing the time from the list of persisted notifications.
+ //IT IS NOT IDEMPOTENT!
+ @NonNull
+ protected Long getSnoozeTimeForUnpostedNotification(int userId, String pkg, String key) {
+ Long time;
+ synchronized (mPersistedSnoozedNotifications) {
+ time = removeRecord(pkg, key, userId, mPersistedSnoozedNotifications);
+ }
+ if (time == null) {
+ return 0L;
+ }
+ return time;
+ }
+
+ protected String getSnoozeContextForUnpostedNotification(int userId, String pkg, String key) {
+ synchronized (mPersistedSnoozedNotificationsWithContext) {
+ return removeRecord(pkg, key, userId, mPersistedSnoozedNotificationsWithContext);
+ }
+ }
+
protected boolean isSnoozed(int userId, String pkg, String key) {
return mSnoozedNotifications.containsKey(userId)
&& mSnoozedNotifications.get(userId).containsKey(pkg)
@@ -169,32 +223,82 @@
* Snoozes a notification and schedules an alarm to repost at that time.
*/
protected void snooze(NotificationRecord record, long duration) {
+ String pkg = record.sbn.getPackageName();
+ String key = record.getKey();
+ int userId = record.getUser().getIdentifier();
+
snooze(record);
- scheduleRepost(record.sbn.getPackageName(), record.getKey(), record.getUserId(), duration);
+ scheduleRepost(pkg, key, userId, duration);
+ Long activateAt = System.currentTimeMillis() + duration;
+ synchronized (mPersistedSnoozedNotifications) {
+ storeRecord(pkg, key, userId, mPersistedSnoozedNotifications, activateAt);
+ }
}
/**
* Records a snoozed notification.
*/
- protected void snooze(NotificationRecord record) {
+ protected void snooze(NotificationRecord record, String contextId) {
+ int userId = record.getUser().getIdentifier();
+ if (contextId != null) {
+ synchronized (mPersistedSnoozedNotificationsWithContext) {
+ storeRecord(record.sbn.getPackageName(), record.getKey(),
+ userId, mPersistedSnoozedNotificationsWithContext, contextId);
+ }
+ }
+ snooze(record);
+ }
+
+ private void snooze(NotificationRecord record) {
int userId = record.getUser().getIdentifier();
if (DEBUG) {
Slog.d(TAG, "Snoozing " + record.getKey());
}
- ArrayMap<String, ArrayMap<String, NotificationRecord>> records =
- mSnoozedNotifications.get(userId);
+ storeRecord(record.sbn.getPackageName(), record.getKey(),
+ userId, mSnoozedNotifications, record);
+ mPackages.put(record.getKey(), record.sbn.getPackageName());
+ mUsers.put(record.getKey(), userId);
+ }
+
+ private <T> void storeRecord(String pkg, String key, Integer userId,
+ ArrayMap<Integer, ArrayMap<String, ArrayMap<String, T>>> targets, T object) {
+
+ ArrayMap<String, ArrayMap<String, T>> records =
+ targets.get(userId);
if (records == null) {
records = new ArrayMap<>();
}
- ArrayMap<String, NotificationRecord> pkgRecords = records.get(record.sbn.getPackageName());
+ ArrayMap<String, T> pkgRecords = records.get(pkg);
if (pkgRecords == null) {
pkgRecords = new ArrayMap<>();
}
- pkgRecords.put(record.getKey(), record);
- records.put(record.sbn.getPackageName(), pkgRecords);
- mSnoozedNotifications.put(userId, records);
- mPackages.put(record.getKey(), record.sbn.getPackageName());
- mUsers.put(record.getKey(), userId);
+ pkgRecords.put(key, object);
+ records.put(pkg, pkgRecords);
+ targets.put(userId, records);
+
+ }
+
+ private <T> T removeRecord(String pkg, String key, Integer userId,
+ ArrayMap<Integer, ArrayMap<String, ArrayMap<String, T>>> targets) {
+ T object = null;
+
+ ArrayMap<String, ArrayMap<String, T>> records =
+ targets.get(userId);
+ if (records == null) {
+ return null;
+ }
+ ArrayMap<String, T> pkgRecords = records.get(pkg);
+ if (pkgRecords == null) {
+ return null;
+ }
+ object = pkgRecords.remove(key);
+ if (pkgRecords.size() == 0) {
+ records.remove(pkg);
+ }
+ if (records.size() == 0) {
+ targets.remove(userId);
+ }
+ return object;
}
protected boolean cancel(int userId, String pkg, String tag, int id) {
@@ -414,13 +518,121 @@
}
}
- protected void writeXml(XmlSerializer out, boolean forBackup) throws IOException {
-
+ protected void writeXml(XmlSerializer out) throws IOException {
+ final long currentTime = System.currentTimeMillis();
+ out.startTag(null, XML_TAG_NAME);
+ writeXml(out, mPersistedSnoozedNotifications, XML_SNOOZED_NOTIFICATION,
+ value -> {
+ if (value < currentTime) {
+ return;
+ }
+ out.attribute(null, XML_SNOOZED_NOTIFICATION_TIME,
+ value.toString());
+ });
+ writeXml(out, mPersistedSnoozedNotificationsWithContext, XML_SNOOZED_NOTIFICATION_CONTEXT,
+ value -> {
+ out.attribute(null, XML_SNOOZED_NOTIFICATION_CONTEXT_ID,
+ value);
+ });
+ out.endTag(null, XML_TAG_NAME);
}
- public void readXml(XmlPullParser parser, boolean forRestore)
- throws XmlPullParserException, IOException {
+ private interface Inserter<T> {
+ void insert(T t) throws IOException;
+ }
+ private <T> void writeXml(XmlSerializer out,
+ ArrayMap<Integer, ArrayMap<String, ArrayMap<String, T>>> targets, String tag,
+ Inserter<T> attributeInserter)
+ throws IOException {
+ synchronized (targets) {
+ final int M = targets.size();
+ for (int i = 0; i < M; i++) {
+ final ArrayMap<String, ArrayMap<String, T>> packages =
+ targets.valueAt(i);
+ if (packages == null) {
+ continue;
+ }
+ final int N = packages.size();
+ for (int j = 0; j < N; j++) {
+ final ArrayMap<String, T> keyToValue = packages.valueAt(j);
+ if (keyToValue == null) {
+ continue;
+ }
+ final int O = keyToValue.size();
+ for (int k = 0; k < O; k++) {
+ T value = keyToValue.valueAt(k);
+ out.startTag(null, tag);
+
+ attributeInserter.insert(value);
+
+ out.attribute(null, XML_SNOOZED_NOTIFICATION_VERSION_LABEL,
+ XML_SNOOZED_NOTIFICATION_VERSION);
+ out.attribute(null, XML_SNOOZED_NOTIFICATION_KEY, keyToValue.keyAt(k));
+ out.attribute(null, XML_SNOOZED_NOTIFICATION_PKG, packages.keyAt(j));
+ out.attribute(null, XML_SNOOZED_NOTIFICATION_USER_ID,
+ targets.keyAt(i).toString());
+
+ out.endTag(null, tag);
+
+ }
+ }
+ }
+ }
+ }
+
+ protected void readXml(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
+ String tag = parser.getName();
+ if (type == XmlPullParser.END_TAG
+ && XML_TAG_NAME.equals(tag)) {
+ break;
+ }
+ if (type == XmlPullParser.START_TAG
+ && (XML_SNOOZED_NOTIFICATION.equals(tag)
+ || tag.equals(XML_SNOOZED_NOTIFICATION_CONTEXT))
+ && parser.getAttributeValue(null, XML_SNOOZED_NOTIFICATION_VERSION_LABEL)
+ .equals(XML_SNOOZED_NOTIFICATION_VERSION)) {
+ try {
+ final String key = parser.getAttributeValue(null, XML_SNOOZED_NOTIFICATION_KEY);
+ final String pkg = parser.getAttributeValue(null, XML_SNOOZED_NOTIFICATION_PKG);
+ final int userId = Integer.parseInt(
+ parser.getAttributeValue(null, XML_SNOOZED_NOTIFICATION_USER_ID));
+ if (tag.equals(XML_SNOOZED_NOTIFICATION)) {
+ final Long time = Long.parseLong(
+ parser.getAttributeValue(null, XML_SNOOZED_NOTIFICATION_TIME));
+ if (time > System.currentTimeMillis()) { //only read new stuff
+ synchronized (mPersistedSnoozedNotifications) {
+ storeRecord(pkg, key, userId, mPersistedSnoozedNotifications, time);
+ }
+ scheduleRepost(pkg, key, userId, time - System.currentTimeMillis());
+ }
+ continue;
+ }
+ if (tag.equals(XML_SNOOZED_NOTIFICATION_CONTEXT)) {
+ final String creationId = parser.getAttributeValue(
+ null, XML_SNOOZED_NOTIFICATION_CONTEXT_ID);
+ synchronized (mPersistedSnoozedNotificationsWithContext) {
+ storeRecord(pkg, key, userId, mPersistedSnoozedNotificationsWithContext,
+ creationId);
+ }
+ continue;
+ }
+
+
+ } catch (Exception e) {
+ //we dont cre if it is a number format exception or a null pointer exception.
+ //we just want to debug it and continue with our lives
+ if (DEBUG) {
+ Slog.d(TAG,
+ "Exception in reading snooze data from policy xml: "
+ + e.getMessage());
+ }
+ }
+ }
+ }
}
@VisibleForTesting
diff --git a/services/core/java/com/android/server/om/IdmapDaemon.java b/services/core/java/com/android/server/om/IdmapDaemon.java
index 91824c3..20a4c75 100644
--- a/services/core/java/com/android/server/om/IdmapDaemon.java
+++ b/services/core/java/com/android/server/om/IdmapDaemon.java
@@ -129,11 +129,11 @@
}
}
- static void startIdmapService() {
+ private static void startIdmapService() {
SystemProperties.set("ctl.start", IDMAP_DAEMON);
}
- static void stopIdmapService() {
+ private static void stopIdmapService() {
SystemProperties.set("ctl.stop", IDMAP_DAEMON);
}
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index ce95181..965ddc9 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -262,7 +262,6 @@
initIfNeeded();
onSwitchUser(UserHandle.USER_SYSTEM);
- IdmapDaemon.stopIdmapService();
publishBinderService(Context.OVERLAY_SERVICE, mService);
publishLocalService(OverlayManagerService.class, this);
@@ -752,7 +751,7 @@
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
final DumpState dumpState = new DumpState();
- dumpState.setUserId(UserHandle.getUserId(Binder.getCallingUid()));
+ dumpState.setUserId(UserHandle.USER_ALL);
int opti = 0;
while (opti < args.length) {
@@ -772,13 +771,13 @@
pw.println(" so the following are equivalent: mState, mstate, State, state.");
return;
} else if ("--user".equals(opt)) {
- opti++;
if (opti >= args.length) {
pw.println("Error: user missing argument");
return;
}
try {
dumpState.setUserId(Integer.parseInt(args[opti]));
+ opti++;
} catch (NumberFormatException e) {
pw.println("Error: user argument is not a number: " + args[opti]);
return;
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 7b13720..7eb7438 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -16,10 +16,10 @@
package com.android.server.pm;
+import static android.provider.DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE;
+
import android.Manifest;
import android.annotation.Nullable;
-import android.app.AppOpsManager;
-import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
@@ -35,6 +35,7 @@
import com.android.internal.R;
import com.android.server.FgThread;
+import com.android.server.compat.PlatformCompat;
import java.io.PrintWriter;
import java.util.Collections;
@@ -43,7 +44,6 @@
import java.util.Map;
import java.util.Objects;
import java.util.Set;
-import java.util.concurrent.atomic.AtomicInteger;
/**
* The entity responsible for filtering visibility between apps based on declarations in their
@@ -100,14 +100,11 @@
private final IPermissionManager mPermissionManager;
- private final AppOpsManager mAppOpsManager;
- private final ConfigProvider mConfigProvider;
+ private final FeatureConfig mFeatureConfig;
- AppsFilter(ConfigProvider configProvider, IPermissionManager permissionManager,
- AppOpsManager appOpsManager, String[] forceQueryableWhitelist,
- boolean systemAppsQueryable) {
- mConfigProvider = configProvider;
- mAppOpsManager = appOpsManager;
+ AppsFilter(FeatureConfig featureConfig, IPermissionManager permissionManager,
+ String[] forceQueryableWhitelist, boolean systemAppsQueryable) {
+ mFeatureConfig = featureConfig;
final HashSet<String> forceQueryableByDeviceSet = new HashSet<>();
Collections.addAll(forceQueryableByDeviceSet, forceQueryableWhitelist);
this.mForceQueryableByDevice = Collections.unmodifiableSet(forceQueryableByDeviceSet);
@@ -116,39 +113,83 @@
mSystemAppsQueryable = systemAppsQueryable;
}
- public static AppsFilter create(Context context) {
- // tracks whether the feature is enabled where -1 is unknown, 0 is false and 1 is true;
- final AtomicInteger featureEnabled = new AtomicInteger(-1);
+ public interface FeatureConfig {
+ /** Called when the system is ready and components can be queried. */
+ void onSystemReady();
+ /** @return true if we should filter apps at all. */
+ boolean isGloballyEnabled();
+
+ /** @return true if the feature is enabled for the given package. */
+ boolean packageIsEnabled(PackageParser.Package pkg);
+ }
+
+ private static class FeatureConfigImpl implements FeatureConfig {
+ private static final String FILTERING_ENABLED_NAME = "package_query_filtering_enabled";
+
+ // STOPSHIP(patb): set this to true if we plan to launch this in R
+ private static final boolean DEFAULT_ENABLED_STATE = false;
+ private final PackageManagerService.Injector mInjector;
+ private volatile boolean mFeatureEnabled = DEFAULT_ENABLED_STATE;
+
+ private FeatureConfigImpl(PackageManagerService.Injector injector) {
+ mInjector = injector;
+ }
+
+ @Override
+ public void onSystemReady() {
+ mFeatureEnabled = DeviceConfig.getBoolean(
+ NAMESPACE_PACKAGE_MANAGER_SERVICE, FILTERING_ENABLED_NAME,
+ DEFAULT_ENABLED_STATE);
+ DeviceConfig.addOnPropertiesChangedListener(
+ NAMESPACE_PACKAGE_MANAGER_SERVICE, FgThread.getExecutor(),
+ properties -> {
+ synchronized (FeatureConfigImpl.this) {
+ mFeatureEnabled = properties.getBoolean(
+ FILTERING_ENABLED_NAME, DEFAULT_ENABLED_STATE);
+ }
+ });
+ }
+
+ @Override
+ public boolean isGloballyEnabled() {
+ return mFeatureEnabled;
+ }
+
+ @Override
+ public boolean packageIsEnabled(PackageParser.Package pkg) {
+ final PlatformCompat compatibility = mInjector.getCompatibility();
+ if (compatibility == null) {
+ Slog.wtf(TAG, "PlatformCompat is null");
+ return mFeatureEnabled;
+ }
+ return compatibility.isChangeEnabled(
+ PackageManager.FILTER_APPLICATION_QUERY, pkg.applicationInfo);
+ }
+ }
+
+
+ public static AppsFilter create(PackageManagerService.Injector injector) {
final boolean forceSystemAppsQueryable =
- context.getResources().getBoolean(R.bool.config_forceSystemPackagesQueryable);
+ injector.getContext().getResources()
+ .getBoolean(R.bool.config_forceSystemPackagesQueryable);
+ final FeatureConfig featureConfig = new FeatureConfigImpl(injector);
final String[] forcedQueryablePackageNames;
if (forceSystemAppsQueryable) {
// all system apps already queryable, no need to read and parse individual exceptions
forcedQueryablePackageNames = new String[]{};
} else {
forcedQueryablePackageNames =
- context.getResources().getStringArray(R.array.config_forceQueryablePackages);
+ injector.getContext().getResources()
+ .getStringArray(R.array.config_forceQueryablePackages);
for (int i = 0; i < forcedQueryablePackageNames.length; i++) {
forcedQueryablePackageNames[i] = forcedQueryablePackageNames[i].intern();
}
}
IPermissionManager permissionmgr =
(IPermissionManager) ServiceManager.getService("permissionmgr");
- return new AppsFilter(() -> {
- if (featureEnabled.get() < 0) {
- featureEnabled.set(DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE,
- "package_query_filtering_enabled", false) ? 1 : 0);
- DeviceConfig.addOnPropertiesChangedListener(
- DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE,
- FgThread.getExecutor(),
- pr -> featureEnabled.set(
- pr.getBoolean("package_query_filtering_enabled", false) ? 1 : 0));
- }
- return featureEnabled.get() == 1;
- }, permissionmgr,
- context.getSystemService(AppOpsManager.class), forcedQueryablePackageNames,
+
+ return new AppsFilter(featureConfig, permissionmgr, forcedQueryablePackageNames,
forceSystemAppsQueryable);
}
@@ -200,6 +241,10 @@
currentUser.get(targetPackage.pkg.packageName).add(initiatingPackage.pkg.packageName);
}
+ public void onSystemReady() {
+ mFeatureConfig.onSystemReady();
+ }
+
/**
* Adds a package that should be considered when filtering visibility between apps.
*
@@ -281,11 +326,11 @@
*/
public boolean shouldFilterApplication(int callingUid, @Nullable SettingBase callingSetting,
PackageSetting targetPkgSetting, int userId) {
- if (callingUid < Process.FIRST_APPLICATION_UID) {
+ final boolean featureEnabled = mFeatureConfig.isGloballyEnabled();
+ if (!featureEnabled && !DEBUG_RUN_WHEN_DISABLED) {
return false;
}
- final boolean featureEnabled = mConfigProvider.isEnabled();
- if (!featureEnabled && !DEBUG_RUN_WHEN_DISABLED) {
+ if (callingUid < Process.FIRST_APPLICATION_UID) {
return false;
}
if (callingSetting == null) {
@@ -326,31 +371,21 @@
return true;
}
}
-
if (!featureEnabled) {
return false;
}
- final int mode = mAppOpsManager
- .checkOpNoThrow(AppOpsManager.OP_QUERY_ALL_PACKAGES, callingUid,
- callingPkgSetting.pkg.packageName);
- switch (mode) {
- case AppOpsManager.MODE_DEFAULT:
- if (DEBUG_LOGGING) {
- Slog.d(TAG, "filtered interaction: " + callingPkgSetting.name + " -> "
- + targetPkgSetting.name + (DEBUG_ALLOW_ALL ? " ALLOWED" : ""));
- }
- return !DEBUG_ALLOW_ALL;
- case AppOpsManager.MODE_ALLOWED:
- // explicitly allowed to see all packages, don't filter
- return false;
- case AppOpsManager.MODE_ERRORED:
- // deny / error: let's log so developer can audit usages
- Slog.i(TAG, callingPkgSetting.pkg.packageName
- + " blocked from accessing " + targetPkgSetting.pkg.packageName);
- case AppOpsManager.MODE_IGNORED:
- // fall through
- default:
- return true;
+ if (mFeatureConfig.packageIsEnabled(callingPkgSetting.pkg)) {
+ if (DEBUG_LOGGING) {
+ Slog.d(TAG, "interaction: " + callingPkgSetting.name + " -> "
+ + targetPkgSetting.name + (DEBUG_ALLOW_ALL ? " ALLOWED" : "BLOCKED"));
+ }
+ return !DEBUG_ALLOW_ALL;
+ } else {
+ if (DEBUG_LOGGING) {
+ Slog.d(TAG, "interaction: " + callingPkgSetting.name + " -> "
+ + targetPkgSetting.name + " DISABLED");
+ }
+ return false;
}
}
@@ -391,6 +426,13 @@
&& mImplicitlyQueryable.get(userId).get(callingName).contains(targetName)) {
return false;
}
+ if (callingPkgSetting.pkg.instrumentation.size() > 0) {
+ for (int i = 0, max = callingPkgSetting.pkg.instrumentation.size(); i < max; i++) {
+ if (callingPkgSetting.pkg.instrumentation.get(i).info.targetPackage == targetName) {
+ return false;
+ }
+ }
+ }
try {
if (mPermissionManager.checkPermission(
Manifest.permission.QUERY_ALL_PACKAGES, callingName, userId)
@@ -414,7 +456,6 @@
pw.println();
pw.println("Queries:");
dumpState.onTitlePrinted();
- pw.println(" enabled: " + mConfigProvider.isEnabled());
pw.println(" system apps queryable: " + mSystemAppsQueryable);
dumpPackageSet(pw, filteringPackageName, mForceQueryableByDevice, "System whitelist", " ");
dumpPackageSet(pw, filteringPackageName, mForceQueryable, "forceQueryable", " ");
@@ -456,9 +497,4 @@
}
}
}
-
- public interface ConfigProvider {
- boolean isEnabled();
- }
-
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 0032e9a..3aeb2b1 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -1184,9 +1184,26 @@
synchronized (mSessions) {
pw.println("Active install sessions:");
pw.increaseIndent();
+
+ List<PackageInstallerSession> finalizedSessions = new ArrayList<>();
int N = mSessions.size();
for (int i = 0; i < N; i++) {
final PackageInstallerSession session = mSessions.valueAt(i);
+ if (session.isStagedAndInTerminalState()) {
+ finalizedSessions.add(session);
+ continue;
+ }
+ session.dump(pw);
+ pw.println();
+ }
+ pw.println();
+ pw.decreaseIndent();
+
+ pw.println("Finalized install sessions:");
+ pw.increaseIndent();
+ N = finalizedSessions.size();
+ for (int i = 0; i < N; i++) {
+ final PackageInstallerSession session = finalizedSessions.get(i);
session.dump(pw);
pw.println();
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 4eddb930..b720290 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -2337,6 +2337,7 @@
pw.printPair("mInstallerPackageName", mInstallerPackageName);
pw.printPair("mInstallerUid", mInstallerUid);
pw.printPair("createdMillis", createdMillis);
+ pw.printPair("updatedMillis", updatedMillis);
pw.printPair("stageDir", stageDir);
pw.printPair("stageCid", stageCid);
pw.println();
@@ -2356,6 +2357,13 @@
pw.printPair("mFinalMessage", mFinalMessage);
pw.printPair("params.isMultiPackage", params.isMultiPackage);
pw.printPair("params.isStaged", params.isStaged);
+ pw.printPair("mParentSessionId", mParentSessionId);
+ pw.printPair("mChildSessionIds", mChildSessionIds);
+ pw.printPair("mStagedSessionApplied", mStagedSessionApplied);
+ pw.printPair("mStagedSessionFailed", mStagedSessionFailed);
+ pw.printPair("mStagedSessionReady", mStagedSessionReady);
+ pw.printPair("mStagedSessionErrorCode", mStagedSessionErrorCode);
+ pw.printPair("mStagedSessionErrorMessage", mStagedSessionErrorMessage);
pw.println();
pw.decreaseIndent();
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index af20346..15a3a72 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -290,7 +290,7 @@
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.server.AttributeCache;
-import com.android.server.DeviceIdleController;
+import com.android.server.DeviceIdleInternal;
import com.android.server.EventLogTags;
import com.android.server.FgThread;
import com.android.server.LocalServices;
@@ -300,6 +300,7 @@
import com.android.server.SystemConfig;
import com.android.server.SystemServerInitThreadPool;
import com.android.server.Watchdog;
+import com.android.server.compat.PlatformCompat;
import com.android.server.net.NetworkPolicyManagerInternal;
import com.android.server.pm.Installer.InstallerException;
import com.android.server.pm.Settings.DatabaseVersion;
@@ -816,7 +817,7 @@
private final Singleton<UserManagerService> mUserManagerProducer;
private final Singleton<Settings> mSettingsProducer;
private final Singleton<ActivityTaskManagerInternal> mActivityTaskManagerProducer;
- private final Singleton<DeviceIdleController.LocalService> mLocalDeviceIdleController;
+ private final Singleton<DeviceIdleInternal> mLocalDeviceIdleController;
private final Singleton<StorageManagerInternal> mStorageManagerInternalProducer;
private final Singleton<NetworkPolicyManagerInternal> mNetworkPolicyManagerProducer;
private final Singleton<PermissionPolicyInternal> mPermissionPolicyProducer;
@@ -824,6 +825,8 @@
private final Singleton<DisplayManager> mDisplayManagerProducer;
private final Singleton<StorageManager> mStorageManagerProducer;
private final Singleton<AppOpsManager> mAppOpsManagerProducer;
+ private final Singleton<AppsFilter> mAppsFilterProducer;
+ private final Singleton<PlatformCompat> mPlatformCompatProducer;
Injector(Context context, Object lock, Installer installer,
Object installLock, PackageAbiHelper abiHelper,
@@ -832,14 +835,16 @@
Producer<UserManagerService> userManagerProducer,
Producer<Settings> settingsProducer,
Producer<ActivityTaskManagerInternal> activityTaskManagerProducer,
- Producer<DeviceIdleController.LocalService> deviceIdleControllerProducer,
+ Producer<DeviceIdleInternal> deviceIdleControllerProducer,
Producer<StorageManagerInternal> storageManagerInternalProducer,
Producer<NetworkPolicyManagerInternal> networkPolicyManagerProducer,
Producer<PermissionPolicyInternal> permissionPolicyProvider,
Producer<DeviceStorageMonitorInternal> deviceStorageMonitorProducer,
Producer<DisplayManager> displayManagerProducer,
Producer<StorageManager> storageManagerProducer,
- Producer<AppOpsManager> appOpsManagerProducer) {
+ Producer<AppOpsManager> appOpsManagerProducer,
+ Producer<AppsFilter> appsFilterProducer,
+ Producer<PlatformCompat> platformCompatProducer) {
mContext = context;
mLock = lock;
mInstaller = installer;
@@ -858,6 +863,8 @@
mDisplayManagerProducer = new Singleton<>(displayManagerProducer);
mStorageManagerProducer = new Singleton<>(storageManagerProducer);
mAppOpsManagerProducer = new Singleton<>(appOpsManagerProducer);
+ mAppsFilterProducer = new Singleton<>(appsFilterProducer);
+ mPlatformCompatProducer = new Singleton<>(platformCompatProducer);
}
/**
@@ -912,7 +919,7 @@
return mActivityTaskManagerProducer.get(this, mPackageManager);
}
- public DeviceIdleController.LocalService getLocalDeviceIdleController() {
+ public DeviceIdleInternal getLocalDeviceIdleController() {
return mLocalDeviceIdleController.get(this, mPackageManager);
}
@@ -943,6 +950,14 @@
public AppOpsManager getAppOpsManager() {
return mAppOpsManagerProducer.get(this, mPackageManager);
}
+
+ public AppsFilter getAppsFilter() {
+ return mAppsFilterProducer.get(this, mPackageManager);
+ }
+
+ public PlatformCompat getCompatibility() {
+ return mPlatformCompatProducer.get(this, mPackageManager);
+ }
}
private final AppsFilter mAppsFilter;
@@ -1249,7 +1264,7 @@
final BroadcastOptions options = BroadcastOptions.makeBasic();
options.setTemporaryAppWhitelistDuration(whitelistTimeout);
- DeviceIdleController.LocalService idleController =
+ DeviceIdleInternal idleController =
mInjector.getLocalDeviceIdleController();
idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
mIntentFilterVerifierComponent.getPackageName(), whitelistTimeout,
@@ -2273,9 +2288,9 @@
* @param packageVolume The storage volume of the package.
* @param packageIsExternal true if the package is currently installed on
* external/removable/unprotected storage.
- * @return {@link StorageEnum#TYPE_UNKNOWN} if the package is not stored externally or the
- * corresponding {@link StorageEnum} storage type value if it is.
- * corresponding {@link StorageEnum} storage type value if it is.
+ * @return {@link StorageEnums#UNKNOWN} if the package is not stored externally or the
+ * corresponding {@link StorageEnums} storage type value if it is.
+ * corresponding {@link StorageEnums} storage type value if it is.
*/
private static int getPackageExternalStorageType(VolumeInfo packageVolume,
boolean packageIsExternal) {
@@ -2425,14 +2440,16 @@
i.getPermissionManagerServiceInternal().getPermissionSettings(),
lock),
new Injector.LocalServicesProducer<>(ActivityTaskManagerInternal.class),
- new Injector.LocalServicesProducer<>(DeviceIdleController.LocalService.class),
+ new Injector.LocalServicesProducer<>(DeviceIdleInternal.class),
new Injector.LocalServicesProducer<>(StorageManagerInternal.class),
new Injector.LocalServicesProducer<>(NetworkPolicyManagerInternal.class),
new Injector.LocalServicesProducer<>(PermissionPolicyInternal.class),
new Injector.LocalServicesProducer<>(DeviceStorageMonitorInternal.class),
new Injector.SystemServiceProducer<>(DisplayManager.class),
new Injector.SystemServiceProducer<>(StorageManager.class),
- new Injector.SystemServiceProducer<>(AppOpsManager.class));
+ new Injector.SystemServiceProducer<>(AppOpsManager.class),
+ (i, pm) -> AppsFilter.create(i),
+ (i, pm) -> (PlatformCompat) ServiceManager.getService("platform_compat"));
PackageManagerService m = new PackageManagerService(injector, factoryTest, onlyCore);
t.traceEnd(); // "create package manager"
@@ -2617,7 +2634,7 @@
mProtectedPackages = new ProtectedPackages(mContext);
mApexManager = ApexManager.create(mContext);
- mAppsFilter = AppsFilter.create(mContext);
+ mAppsFilter = mInjector.getAppsFilter();
// CHECKSTYLE:OFF IndentationCheck
synchronized (mInstallLock) {
@@ -2725,14 +2742,10 @@
mIsPreNMR1Upgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N_MR1;
mIsPreQUpgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.Q;
- int preUpgradeSdkVersion = ver.sdkVersion;
-
// save off the names of pre-existing system packages prior to scanning; we don't
// want to automatically grant runtime permissions for new system apps
if (mPromoteSystemApps) {
- Iterator<PackageSetting> pkgSettingIter = mSettings.mPackages.values().iterator();
- while (pkgSettingIter.hasNext()) {
- PackageSetting ps = pkgSettingIter.next();
+ for (PackageSetting ps : mSettings.mPackages.values()) {
if (isSystemApp(ps)) {
mExistingSystemPackages.add(ps.name);
}
@@ -14511,7 +14524,7 @@
final List<ComponentName> sufficientVerifiers = matchVerifiers(pkgLite,
receivers, verificationState);
- DeviceIdleController.LocalService idleController =
+ DeviceIdleInternal idleController =
mInjector.getLocalDeviceIdleController();
final long idleDuration = getVerificationTimeout();
@@ -14580,17 +14593,6 @@
TRACE_TAG_PACKAGE_MANAGER, "enable_rollback", enableRollbackToken);
mPendingEnableRollback.append(enableRollbackToken, this);
- final int[] installedUsers;
- synchronized (mLock) {
- PackageSetting ps = mSettings.getPackageLPr(pkgLite.packageName);
- if (ps != null) {
- installedUsers = ps.queryInstalledUsers(mUserManager.getUserIds(),
- true);
- } else {
- installedUsers = new int[0];
- }
- }
-
Intent enableRollbackIntent = new Intent(Intent.ACTION_PACKAGE_ENABLE_ROLLBACK);
enableRollbackIntent.putExtra(
PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN,
@@ -14599,9 +14601,6 @@
PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALL_FLAGS,
installFlags);
enableRollbackIntent.putExtra(
- PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALLED_USERS,
- installedUsers);
- enableRollbackIntent.putExtra(
PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_USER,
getRollbackUser().getIdentifier());
enableRollbackIntent.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)),
@@ -20459,6 +20458,8 @@
.getUriFor(Secure.INSTANT_APPS_ENABLED), false, co, UserHandle.USER_ALL);
co.onChange(true);
+ mAppsFilter.onSystemReady();
+
// Disable any carrier apps. We do this very early in boot to prevent the apps from being
// disabled after already being started.
CarrierAppUtils.disableCarrierAppsUntilPrivileged(mContext.getOpPackageName(), this,
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 6d3424c..dd1eb83 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -35,7 +35,6 @@
import android.content.pm.PackageParser.SigningDetails;
import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion;
import android.content.pm.ParceledListSlice;
-import android.content.pm.Signature;
import android.content.rollback.IRollbackManager;
import android.os.Bundle;
import android.os.Handler;
@@ -106,8 +105,19 @@
return new ParceledListSlice<>(result);
}
- private void validateApexSignature(String apexPath, String packageName)
+ /**
+ * Validates the signature used to sign the container of the new apex package
+ *
+ * @param newApexPkg The new apex package that is being installed
+ * @param installFlags flags related to the session
+ * @throws PackageManagerException
+ */
+ private void validateApexSignature(PackageInfo newApexPkg, int installFlags)
throws PackageManagerException {
+ // Get signing details of the new package
+ final String apexPath = newApexPkg.applicationInfo.sourceDir;
+ final String packageName = newApexPkg.packageName;
+
final SigningDetails signingDetails;
try {
signingDetails = ApkSignatureVerifier.verify(apexPath, SignatureSchemeVersion.JAR);
@@ -116,9 +126,10 @@
"Failed to parse APEX package " + apexPath, e);
}
- final PackageInfo packageInfo = mApexManager.getPackageInfo(packageName,
+ // Get signing details of the existing package
+ final PackageInfo existingApexPkg = mApexManager.getPackageInfo(packageName,
ApexManager.MATCH_ACTIVE_PACKAGE);
- if (packageInfo == null) {
+ if (existingApexPkg == null) {
// This should never happen, because submitSessionToApexService ensures that no new
// apexes were installed.
throw new IllegalStateException("Unknown apex package " + packageName);
@@ -127,22 +138,22 @@
final SigningDetails existingSigningDetails;
try {
existingSigningDetails = ApkSignatureVerifier.verify(
- packageInfo.applicationInfo.sourceDir, SignatureSchemeVersion.JAR);
+ existingApexPkg.applicationInfo.sourceDir, SignatureSchemeVersion.JAR);
} catch (PackageParserException e) {
throw new PackageManagerException(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
- "Failed to parse APEX package " + packageInfo.applicationInfo.sourceDir, e);
+ "Failed to parse APEX package " + existingApexPkg.applicationInfo.sourceDir, e);
}
- // Now that we have both sets of signatures, demand that they're an exact match.
- if (Signature.areExactMatch(existingSigningDetails.signatures, signingDetails.signatures)) {
+ // Verify signing details for upgrade
+ if (signingDetails.checkCapability(existingSigningDetails,
+ PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)) {
return;
}
throw new PackageManagerException(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
- "APK-container signature verification failed for package "
- + packageName + ". Signature of file "
- + apexPath + " does not match the signature of "
- + " the package already installed.");
+ "APK-container signature of APEX package " + packageName + " with version "
+ + newApexPkg.versionCodeMajor + " and path " + apexPath + " is not"
+ + " compatible with the one currently installed on device");
}
private List<PackageInfo> submitSessionToApexService(
@@ -239,8 +250,7 @@
try {
final List<PackageInfo> apexPackages = submitSessionToApexService(session);
for (PackageInfo apexPackage : apexPackages) {
- validateApexSignature(apexPackage.applicationInfo.sourceDir,
- apexPackage.packageName);
+ validateApexSignature(apexPackage, session.params.installFlags);
}
} catch (PackageManagerException e) {
session.setStagedSessionFailed(e.error, e.getMessage());
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 2ccb6c1..1fe5512 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -2252,14 +2252,10 @@
@GuardedBy({"mPackagesLock", "mRestrictionsLock"})
private void fallbackToSingleUserLP() {
- int flags = UserInfo.FLAG_SYSTEM | UserInfo.FLAG_INITIALIZED;
- // In split system user mode, the admin and primary flags are assigned to the first human
- // user.
- if (!UserManager.isSplitSystemUser()) {
- flags |= UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY;
- }
+ int flags = UserInfo.FLAG_SYSTEM | UserInfo.FLAG_INITIALIZED | UserInfo.FLAG_ADMIN;
+ // In headless system user mode, the primary flag is assigned to the first human user.
if (!UserManager.isHeadlessSystemUserMode()) {
- flags |= UserInfo.FLAG_FULL;
+ flags |= UserInfo.FLAG_PRIMARY | UserInfo.FLAG_FULL;
}
// Create the system user
UserInfo system = new UserInfo(UserHandle.USER_SYSTEM, null, null, flags);
@@ -2773,9 +2769,9 @@
return null;
}
}
- // In split system user mode, we assign the first human user the primary flag.
+ // In headless system user mode, we assign the first human user the primary flag.
// And if there is no device owner, we also assign the admin flag to primary user.
- if (UserManager.isSplitSystemUser()
+ if (UserManager.isHeadlessSystemUserMode()
&& !isGuest && !isManagedProfile && getPrimaryUser() == null) {
flags |= UserInfo.FLAG_PRIMARY;
synchronized (mUsersLock) {
@@ -3762,6 +3758,8 @@
pw.print(" <partial>");
}
pw.println();
+ pw.print(" Flags: "); pw.print(userInfo.flags); pw.print(" (");
+ pw.print(UserInfo.flagsToString(userInfo.flags)); pw.println(")");
pw.print(" State: ");
final int state;
synchronized (mUserStates) {
@@ -3846,6 +3844,8 @@
pw.println(" All guests ephemeral: " + Resources.getSystem().getBoolean(
com.android.internal.R.bool.config_guestUserEphemeral));
pw.println(" Is split-system user: " + UserManager.isSplitSystemUser());
+ pw.println(" Is headless-system mode: " + UserManager.isHeadlessSystemUserMode());
+ pw.println(" User version: " + mUserVersion);
}
private static void dumpTimeAgo(PrintWriter pw, StringBuilder sb, long nowTime, long time) {
@@ -4172,6 +4172,14 @@
Bundle restrictions = getEffectiveUserRestrictions(userId);
return restrictions != null && restrictions.getBoolean(restrictionKey);
}
+
+ public @Nullable UserInfo getUserInfo(@UserIdInt int userId) {
+ UserData userData;
+ synchronized (mUsersLock) {
+ userData = mUsers.get(userId);
+ }
+ return userData == null ? null : userData.info;
+ }
}
/* Remove all the users except of the system one. */
diff --git a/services/core/java/com/android/server/pm/permission/TEST_MAPPING b/services/core/java/com/android/server/pm/permission/TEST_MAPPING
index af94e44..c0d71ac 100644
--- a/services/core/java/com/android/server/pm/permission/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/permission/TEST_MAPPING
@@ -62,5 +62,10 @@
}
]
}
+ ],
+ "imports": [
+ {
+ "path": "vendor/xts/gts-tests/tests/permission"
+ }
]
}
diff --git a/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java b/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java
index f5f7d67..cae09ea3 100644
--- a/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java
+++ b/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java
@@ -52,12 +52,13 @@
}
/**
- * Creates an app data snapshot for a specified {@code packageRollbackInfo}. Updates said {@code
- * packageRollbackInfo} with the inodes of the CE user data snapshot folders.
+ * Creates an app data snapshot for a specified {@code packageRollbackInfo} and the specified
+ * {@code userIds}. Updates said {@code packageRollbackInfo} with the inodes of the CE user data
+ * snapshot folders.
*/
- public void snapshotAppData(int snapshotId, PackageRollbackInfo packageRollbackInfo) {
- final int[] installedUsers = packageRollbackInfo.getInstalledUsers().toArray();
- for (int user : installedUsers) {
+ public void snapshotAppData(
+ int snapshotId, PackageRollbackInfo packageRollbackInfo, int[] userIds) {
+ for (int user : userIds) {
final int storageFlags;
if (isUserCredentialLocked(user)) {
// We've encountered a user that hasn't unlocked on a FBE device, so we can't copy
@@ -80,6 +81,7 @@
+ packageRollbackInfo.getPackageName() + ", userId: " + user, ie);
}
}
+ packageRollbackInfo.getSnapshottedUsers().addAll(IntArray.wrap(userIds));
}
/**
@@ -96,14 +98,14 @@
final IntArray pendingBackups = packageRollbackInfo.getPendingBackups();
final List<RestoreInfo> pendingRestores = packageRollbackInfo.getPendingRestores();
- boolean changedRollbackData = false;
+ boolean changedRollback = false;
// If we still have a userdata backup pending for this user, it implies that the user
// hasn't unlocked their device between the point of backup and the point of restore,
// so the data cannot have changed. We simply skip restoring CE data in this case.
if (pendingBackups != null && pendingBackups.indexOf(userId) != -1) {
pendingBackups.remove(pendingBackups.indexOf(userId));
- changedRollbackData = true;
+ changedRollback = true;
} else {
// There's no pending CE backup for this user, which means that we successfully
// managed to backup data for the user, which means we seek to restore it
@@ -111,7 +113,7 @@
// We've encountered a user that hasn't unlocked on a FBE device, so we can't
// copy across app user data until the user unlocks their device.
pendingRestores.add(new RestoreInfo(userId, appId, seInfo));
- changedRollbackData = true;
+ changedRollback = true;
} else {
// This user has unlocked, we can proceed to restore both CE and DE data.
storageFlags = storageFlags | Installer.FLAG_STORAGE_CE;
@@ -126,7 +128,7 @@
+ packageRollbackInfo.getPackageName(), ie);
}
- return changedRollbackData;
+ return changedRollback;
}
/**
@@ -158,29 +160,29 @@
* Packages pending backup for the given user are added to {@code pendingBackupPackages} along
* with their corresponding {@code PackageRollbackInfo}.
*
- * @return the list of {@code RollbackData} that has pending backups. Note that some of the
+ * @return the list of rollbacks that have pending backups. Note that some of the
* backups won't be performed, because they might be counteracted by pending restores.
*/
- private static List<RollbackData> computePendingBackups(int userId,
+ private static List<Rollback> computePendingBackups(int userId,
Map<String, PackageRollbackInfo> pendingBackupPackages,
- List<RollbackData> rollbacks) {
- List<RollbackData> rd = new ArrayList<>();
+ List<Rollback> rollbacks) {
+ List<Rollback> rollbacksWithPendingBackups = new ArrayList<>();
- for (RollbackData data : rollbacks) {
- for (PackageRollbackInfo info : data.info.getPackages()) {
+ for (Rollback rollback : rollbacks) {
+ for (PackageRollbackInfo info : rollback.info.getPackages()) {
final IntArray pendingBackupUsers = info.getPendingBackups();
if (pendingBackupUsers != null) {
final int idx = pendingBackupUsers.indexOf(userId);
if (idx != -1) {
pendingBackupPackages.put(info.getPackageName(), info);
- if (rd.indexOf(data) == -1) {
- rd.add(data);
+ if (rollbacksWithPendingBackups.indexOf(rollback) == -1) {
+ rollbacksWithPendingBackups.add(rollback);
}
}
}
}
}
- return rd;
+ return rollbacksWithPendingBackups;
}
/**
@@ -188,45 +190,45 @@
* Packages pending restore are added to {@code pendingRestores} along with their corresponding
* {@code PackageRollbackInfo}.
*
- * @return the list of {@code RollbackData} that has pending restores. Note that some of the
+ * @return the list of rollbacks that have pending restores. Note that some of the
* restores won't be performed, because they might be counteracted by pending backups.
*/
- private static List<RollbackData> computePendingRestores(int userId,
+ private static List<Rollback> computePendingRestores(int userId,
Map<String, PackageRollbackInfo> pendingRestorePackages,
- List<RollbackData> rollbacks) {
- List<RollbackData> rd = new ArrayList<>();
+ List<Rollback> rollbacks) {
+ List<Rollback> rollbacksWithPendingRestores = new ArrayList<>();
- for (RollbackData data : rollbacks) {
- for (PackageRollbackInfo info : data.info.getPackages()) {
+ for (Rollback rollback : rollbacks) {
+ for (PackageRollbackInfo info : rollback.info.getPackages()) {
final RestoreInfo ri = info.getRestoreInfo(userId);
if (ri != null) {
pendingRestorePackages.put(info.getPackageName(), info);
- if (rd.indexOf(data) == -1) {
- rd.add(data);
+ if (rollbacksWithPendingRestores.indexOf(rollback) == -1) {
+ rollbacksWithPendingRestores.add(rollback);
}
}
}
}
- return rd;
+ return rollbacksWithPendingRestores;
}
/**
- * Commits the list of pending backups and restores for a given {@code userId}. For the pending
- * backups updates corresponding {@code changedRollbackData} with a mapping from {@code userId}
- * to a inode of theirs CE user data snapshot.
+ * Commits the list of pending backups and restores for a given {@code userId}. For rollbacks
+ * with pending backups, updates the {@code Rollback} instance with a mapping from
+ * {@code userId} to inode of the CE user data snapshot.
*
- * @return the set of {@code RollbackData} that have been changed and should be stored on disk.
+ * @return the set of rollbacks with changes that should be stored on disk.
*/
- public Set<RollbackData> commitPendingBackupAndRestoreForUser(int userId,
- List<RollbackData> rollbacks) {
+ public Set<Rollback> commitPendingBackupAndRestoreForUser(int userId,
+ List<Rollback> rollbacks) {
final Map<String, PackageRollbackInfo> pendingBackupPackages = new HashMap<>();
- final List<RollbackData> pendingBackups = computePendingBackups(userId,
+ final List<Rollback> pendingBackups = computePendingBackups(userId,
pendingBackupPackages, rollbacks);
final Map<String, PackageRollbackInfo> pendingRestorePackages = new HashMap<>();
- final List<RollbackData> pendingRestores = computePendingRestores(userId,
+ final List<Rollback> pendingRestores = computePendingRestores(userId,
pendingRestorePackages, rollbacks);
// First remove unnecessary backups, i.e. when user did not unlock their phone between the
@@ -246,14 +248,15 @@
}
if (!pendingBackupPackages.isEmpty()) {
- for (RollbackData data : pendingBackups) {
- for (PackageRollbackInfo info : data.info.getPackages()) {
+ for (Rollback rollback : pendingBackups) {
+ for (PackageRollbackInfo info : rollback.info.getPackages()) {
final IntArray pendingBackupUsers = info.getPendingBackups();
final int idx = pendingBackupUsers.indexOf(userId);
if (idx != -1) {
try {
long ceSnapshotInode = mInstaller.snapshotAppData(info.getPackageName(),
- userId, data.info.getRollbackId(), Installer.FLAG_STORAGE_CE);
+ userId, rollback.info.getRollbackId(),
+ Installer.FLAG_STORAGE_CE);
info.putCeSnapshotInode(userId, ceSnapshotInode);
pendingBackupUsers.remove(idx);
} catch (InstallerException ie) {
@@ -267,13 +270,13 @@
}
if (!pendingRestorePackages.isEmpty()) {
- for (RollbackData data : pendingRestores) {
- for (PackageRollbackInfo info : data.info.getPackages()) {
+ for (Rollback rollback : pendingRestores) {
+ for (PackageRollbackInfo info : rollback.info.getPackages()) {
final RestoreInfo ri = info.getRestoreInfo(userId);
if (ri != null) {
try {
mInstaller.restoreAppDataSnapshot(info.getPackageName(), ri.appId,
- ri.seInfo, userId, data.info.getRollbackId(),
+ ri.seInfo, userId, rollback.info.getRollbackId(),
Installer.FLAG_STORAGE_CE);
info.removeRestoreInfo(ri);
} catch (InstallerException ie) {
@@ -285,7 +288,7 @@
}
}
- final Set<RollbackData> changed = new HashSet<>(pendingBackups);
+ final Set<Rollback> changed = new HashSet<>(pendingBackups);
changed.addAll(pendingRestores);
return changed;
}
diff --git a/services/core/java/com/android/server/rollback/RollbackData.java b/services/core/java/com/android/server/rollback/Rollback.java
similarity index 85%
rename from services/core/java/com/android/server/rollback/RollbackData.java
rename to services/core/java/com/android/server/rollback/Rollback.java
index b37e268..0d5746b 100644
--- a/services/core/java/com/android/server/rollback/RollbackData.java
+++ b/services/core/java/com/android/server/rollback/Rollback.java
@@ -32,7 +32,7 @@
* Information about a rollback available for a set of atomically installed
* packages.
*/
-class RollbackData {
+class Rollback {
@IntDef(flag = true, prefix = { "ROLLBACK_STATE_" }, value = {
ROLLBACK_STATE_ENABLING,
ROLLBACK_STATE_AVAILABLE,
@@ -102,13 +102,13 @@
public boolean restoreUserDataInProgress = false;
/**
- * Constructs a new, empty RollbackData instance.
+ * Constructs a new, empty Rollback instance.
*
* @param rollbackId the id of the rollback.
* @param backupDir the directory where the rollback data is stored.
* @param stagedSessionId the session id if this is a staged rollback, -1 otherwise.
*/
- RollbackData(int rollbackId, File backupDir, int stagedSessionId) {
+ Rollback(int rollbackId, File backupDir, int stagedSessionId) {
this.info = new RollbackInfo(rollbackId,
/* packages */ new ArrayList<>(),
/* isStaged */ stagedSessionId != -1,
@@ -121,9 +121,9 @@
}
/**
- * Constructs a RollbackData instance with full rollback data information.
+ * Constructs a pre-populated Rollback instance.
*/
- RollbackData(RollbackInfo info, File backupDir, Instant timestamp, int stagedSessionId,
+ Rollback(RollbackInfo info, File backupDir, Instant timestamp, int stagedSessionId,
@RollbackState int state, int apkSessionId, boolean restoreUserDataInProgress) {
this.info = info;
this.backupDir = backupDir;
@@ -143,9 +143,9 @@
static String rollbackStateToString(@RollbackState int state) {
switch (state) {
- case RollbackData.ROLLBACK_STATE_ENABLING: return "enabling";
- case RollbackData.ROLLBACK_STATE_AVAILABLE: return "available";
- case RollbackData.ROLLBACK_STATE_COMMITTED: return "committed";
+ case Rollback.ROLLBACK_STATE_ENABLING: return "enabling";
+ case Rollback.ROLLBACK_STATE_AVAILABLE: return "available";
+ case Rollback.ROLLBACK_STATE_COMMITTED: return "committed";
}
throw new AssertionError("Invalid rollback state: " + state);
}
@@ -153,9 +153,9 @@
static @RollbackState int rollbackStateFromString(String state)
throws ParseException {
switch (state) {
- case "enabling": return RollbackData.ROLLBACK_STATE_ENABLING;
- case "available": return RollbackData.ROLLBACK_STATE_AVAILABLE;
- case "committed": return RollbackData.ROLLBACK_STATE_COMMITTED;
+ case "enabling": return Rollback.ROLLBACK_STATE_ENABLING;
+ case "available": return Rollback.ROLLBACK_STATE_AVAILABLE;
+ case "committed": return Rollback.ROLLBACK_STATE_COMMITTED;
}
throw new ParseException("Invalid rollback state: " + state, 0);
}
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index f0cf9cf..bfd280c 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -110,13 +110,13 @@
@GuardedBy("mLock")
private final SparseBooleanArray mAllocatedRollbackIds = new SparseBooleanArray();
- // Package rollback data for rollbacks we are in the process of enabling.
+ // Rollbacks we are in the process of enabling.
@GuardedBy("mLock")
private final Set<NewRollback> mNewRollbacks = new ArraySet<>();
// The list of all rollbacks, including available and committed rollbacks.
@GuardedBy("mLock")
- private final List<RollbackData> mRollbacks;
+ private final List<Rollback> mRollbacks;
private final RollbackStore mRollbackStore;
@@ -127,7 +127,7 @@
private final AppDataRollbackHelper mAppDataRollbackHelper;
// This field stores the difference in Millis between the uptime (millis since device
- // has booted) and current time (device wall clock) - it's used to update rollback data
+ // has booted) and current time (device wall clock) - it's used to update rollback
// timestamps when the time is changed, by the user or by change of timezone.
// No need for guarding with lock because value is only accessed in handler thread.
private long mRelativeBootTime = calculateRelativeBootTime();
@@ -146,9 +146,9 @@
// Load rollback data from device storage.
synchronized (mLock) {
- mRollbacks = mRollbackStore.loadAllRollbackData();
- for (RollbackData data : mRollbacks) {
- mAllocatedRollbackIds.put(data.info.getRollbackId(), true);
+ mRollbacks = mRollbackStore.loadRollbacks();
+ for (Rollback rollback : mRollbacks) {
+ mAllocatedRollbackIds.put(rollback.info.getRollbackId(), true);
}
}
@@ -177,16 +177,14 @@
PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN, -1);
int installFlags = intent.getIntExtra(
PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALL_FLAGS, 0);
- int[] installedUsers = intent.getIntArrayExtra(
- PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALLED_USERS);
int user = intent.getIntExtra(
PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_USER, 0);
File newPackageCodePath = new File(intent.getData().getPath());
getHandler().post(() -> {
- boolean success = enableRollback(installFlags, newPackageCodePath,
- installedUsers, user, token);
+ boolean success =
+ enableRollback(installFlags, newPackageCodePath, user, token);
int ret = PackageManagerInternal.ENABLE_ROLLBACK_SUCCEEDED;
if (!success) {
ret = PackageManagerInternal.ENABLE_ROLLBACK_FAILED;
@@ -273,39 +271,24 @@
}, filter, null, getHandler());
}
- /**
- * This method posts a blocking call to the handler thread, so it should not be called from
- * that same thread.
- * @throws {@link IllegalStateException} if called from {@link #mHandlerThread}
- */
@Override
public ParceledListSlice getAvailableRollbacks() {
enforceManageRollbacks("getAvailableRollbacks");
- if (Thread.currentThread().equals(mHandlerThread)) {
- Slog.wtf(TAG, "Calling getAvailableRollbacks from mHandlerThread "
- + "causes a deadlock");
- throw new IllegalStateException("Cannot call RollbackManager#getAvailableRollbacks "
- + "from the handler thread!");
- }
-
- // Wait for the handler thread to get the list of available rollbacks
- // to get the most up-to-date results. This is intended to reduce test
- // flakiness when checking available rollbacks immediately after
- // installing a package with rollback enabled.
- CountDownLatch latch = new CountDownLatch(1);
- getHandler().post(() -> latch.countDown());
- try {
- latch.await();
- } catch (InterruptedException ie) {
- throw new IllegalStateException("RollbackManagerHandlerThread interrupted");
- }
-
synchronized (mLock) {
List<RollbackInfo> rollbacks = new ArrayList<>();
for (int i = 0; i < mRollbacks.size(); ++i) {
- RollbackData data = mRollbacks.get(i);
- if (data.state == RollbackData.ROLLBACK_STATE_AVAILABLE) {
- rollbacks.add(data.info);
+ Rollback rollback = mRollbacks.get(i);
+ if (rollback.state == Rollback.ROLLBACK_STATE_AVAILABLE) {
+ rollbacks.add(rollback.info);
+ }
+ }
+
+ // Also return new rollbacks for which the PackageRollbackInfo is complete.
+ for (NewRollback newRollback : mNewRollbacks) {
+ if (newRollback.rollback.info.getPackages().size()
+ == newRollback.packageSessionIds.length
+ && !newRollback.isCancelled) {
+ rollbacks.add(newRollback.rollback.info);
}
}
return new ParceledListSlice<>(rollbacks);
@@ -319,9 +302,9 @@
synchronized (mLock) {
List<RollbackInfo> rollbacks = new ArrayList<>();
for (int i = 0; i < mRollbacks.size(); ++i) {
- RollbackData data = mRollbacks.get(i);
- if (data.state == RollbackData.ROLLBACK_STATE_COMMITTED) {
- rollbacks.add(data.info);
+ Rollback rollback = mRollbacks.get(i);
+ if (rollback.state == Rollback.ROLLBACK_STATE_COMMITTED) {
+ rollbacks.add(rollback.info);
}
}
return new ParceledListSlice<>(rollbacks);
@@ -351,11 +334,11 @@
final long timeDifference = mRelativeBootTime - oldRelativeBootTime;
synchronized (mLock) {
- Iterator<RollbackData> iter = mRollbacks.iterator();
+ Iterator<Rollback> iter = mRollbacks.iterator();
while (iter.hasNext()) {
- RollbackData data = iter.next();
- data.timestamp = data.timestamp.plusMillis(timeDifference);
- saveRollbackData(data);
+ Rollback rollback = iter.next();
+ rollback.timestamp = rollback.timestamp.plusMillis(timeDifference);
+ saveRollback(rollback);
}
}
}
@@ -379,8 +362,8 @@
String callerPackageName, IntentSender statusReceiver) {
Slog.i(TAG, "Initiating rollback");
- RollbackData data = getRollbackForId(rollbackId);
- if (data == null || data.state != RollbackData.ROLLBACK_STATE_AVAILABLE) {
+ Rollback rollback = getRollbackForId(rollbackId);
+ if (rollback == null || rollback.state != Rollback.ROLLBACK_STATE_AVAILABLE) {
sendFailure(statusReceiver, RollbackManager.STATUS_FAILURE_ROLLBACK_UNAVAILABLE,
"Rollback unavailable");
return;
@@ -404,14 +387,14 @@
PackageInstaller.SessionParams.MODE_FULL_INSTALL);
parentParams.setRequestDowngrade(true);
parentParams.setMultiPackage();
- if (data.isStaged()) {
+ if (rollback.isStaged()) {
parentParams.setStaged();
}
int parentSessionId = packageInstaller.createSession(parentParams);
PackageInstaller.Session parentSession = packageInstaller.openSession(parentSessionId);
- for (PackageRollbackInfo info : data.info.getPackages()) {
+ for (PackageRollbackInfo info : rollback.info.getPackages()) {
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
PackageInstaller.SessionParams.MODE_FULL_INSTALL);
// TODO: We can't get the installerPackageName for apex
@@ -426,7 +409,7 @@
params.setRequestDowngrade(true);
params.setRequiredInstalledVersionCode(
info.getVersionRolledBackFrom().getLongVersionCode());
- if (data.isStaged()) {
+ if (rollback.isStaged()) {
params.setStaged();
}
if (info.isApex()) {
@@ -435,7 +418,7 @@
int sessionId = packageInstaller.createSession(params);
PackageInstaller.Session session = packageInstaller.openSession(sessionId);
File[] packageCodePaths = RollbackStore.getPackageCodePaths(
- data, info.getPackageName());
+ rollback, info.getPackageName());
if (packageCodePaths == null) {
sendFailure(statusReceiver, RollbackManager.STATUS_FAILURE,
"Backup copy of package inaccessible");
@@ -476,8 +459,8 @@
// TODO: Could this cause a rollback to be
// resurrected if it should otherwise have
// expired by now?
- data.state = RollbackData.ROLLBACK_STATE_AVAILABLE;
- data.restoreUserDataInProgress = false;
+ rollback.state = Rollback.ROLLBACK_STATE_AVAILABLE;
+ rollback.restoreUserDataInProgress = false;
}
sendFailure(statusReceiver, RollbackManager.STATUS_FAILURE_INSTALL,
"Rollback downgrade install failed: "
@@ -487,17 +470,17 @@
}
synchronized (mLock) {
- if (!data.isStaged()) {
+ if (!rollback.isStaged()) {
// All calls to restoreUserData should have
// completed by now for a non-staged install.
- data.restoreUserDataInProgress = false;
+ rollback.restoreUserDataInProgress = false;
}
- data.info.setCommittedSessionId(parentSessionId);
- data.info.getCausePackages().addAll(causePackages);
+ rollback.info.setCommittedSessionId(parentSessionId);
+ rollback.info.getCausePackages().addAll(causePackages);
}
- mRollbackStore.deletePackageCodePaths(data);
- saveRollbackData(data);
+ mRollbackStore.deletePackageCodePaths(rollback);
+ saveRollback(rollback);
sendSuccess(statusReceiver);
@@ -512,8 +495,8 @@
);
synchronized (mLock) {
- data.state = RollbackData.ROLLBACK_STATE_COMMITTED;
- data.restoreUserDataInProgress = true;
+ rollback.state = Rollback.ROLLBACK_STATE_COMMITTED;
+ rollback.restoreUserDataInProgress = true;
}
parentSession.commit(receiver.getIntentSender());
} catch (IOException e) {
@@ -535,7 +518,7 @@
updateRollbackLifetimeDurationInMillis();
synchronized (mLock) {
mRollbacks.clear();
- mRollbacks.addAll(mRollbackStore.loadAllRollbackData());
+ mRollbacks.addAll(mRollbackStore.loadRollbacks());
}
latch.countDown();
});
@@ -553,13 +536,21 @@
Manifest.permission.TEST_MANAGE_ROLLBACKS,
"expireRollbackForPackage");
synchronized (mLock) {
- Iterator<RollbackData> iter = mRollbacks.iterator();
+ Iterator<Rollback> iter = mRollbacks.iterator();
while (iter.hasNext()) {
- RollbackData data = iter.next();
- for (PackageRollbackInfo info : data.info.getPackages()) {
+ Rollback rollback = iter.next();
+ for (PackageRollbackInfo info : rollback.info.getPackages()) {
if (info.getPackageName().equals(packageName)) {
iter.remove();
- deleteRollback(data);
+ deleteRollback(rollback);
+ break;
+ }
+ }
+ }
+ for (NewRollback newRollback : mNewRollbacks) {
+ for (PackageRollbackInfo info : newRollback.rollback.info.getPackages()) {
+ if (info.getPackageName().equals(packageName)) {
+ newRollback.isCancelled = true;
break;
}
}
@@ -583,16 +574,16 @@
void onUnlockUser(int userId) {
getHandler().post(() -> {
- final List<RollbackData> rollbacks;
+ final List<Rollback> rollbacks;
synchronized (mLock) {
rollbacks = new ArrayList<>(mRollbacks);
}
- final Set<RollbackData> changed =
+ final Set<Rollback> changed =
mAppDataRollbackHelper.commitPendingBackupAndRestoreForUser(userId, rollbacks);
- for (RollbackData rd : changed) {
- saveRollbackData(rd);
+ for (Rollback rollback : changed) {
+ saveRollback(rollback);
}
});
}
@@ -615,19 +606,19 @@
getHandler().post(() -> {
// Check to see if any rollback-enabled staged sessions or staged
// rollback sessions been applied.
- List<RollbackData> enabling = new ArrayList<>();
- List<RollbackData> restoreInProgress = new ArrayList<>();
+ List<Rollback> enabling = new ArrayList<>();
+ List<Rollback> restoreInProgress = new ArrayList<>();
Set<String> apexPackageNames = new HashSet<>();
synchronized (mLock) {
- for (RollbackData data : mRollbacks) {
- if (data.isStaged()) {
- if (data.state == RollbackData.ROLLBACK_STATE_ENABLING) {
- enabling.add(data);
- } else if (data.restoreUserDataInProgress) {
- restoreInProgress.add(data);
+ for (Rollback rollback : mRollbacks) {
+ if (rollback.isStaged()) {
+ if (rollback.state == Rollback.ROLLBACK_STATE_ENABLING) {
+ enabling.add(rollback);
+ } else if (rollback.restoreUserDataInProgress) {
+ restoreInProgress.add(rollback);
}
- for (PackageRollbackInfo info : data.info.getPackages()) {
+ for (PackageRollbackInfo info : rollback.info.getPackages()) {
if (info.isApex()) {
apexPackageNames.add(info.getPackageName());
}
@@ -636,32 +627,32 @@
}
}
- for (RollbackData data : enabling) {
+ for (Rollback rollback : enabling) {
PackageInstaller installer = mContext.getPackageManager().getPackageInstaller();
PackageInstaller.SessionInfo session = installer.getSessionInfo(
- data.stagedSessionId);
+ rollback.stagedSessionId);
if (session == null || session.isStagedSessionFailed()) {
// TODO: Do we need to remove this from
// mRollbacks, or is it okay to leave as
// unavailable until the next reboot when it will go
// away on its own?
- deleteRollback(data);
+ deleteRollback(rollback);
} else if (session.isStagedSessionApplied()) {
- makeRollbackAvailable(data);
+ makeRollbackAvailable(rollback);
}
}
- for (RollbackData data : restoreInProgress) {
+ for (Rollback rollback : restoreInProgress) {
PackageInstaller installer = mContext.getPackageManager().getPackageInstaller();
PackageInstaller.SessionInfo session = installer.getSessionInfo(
- data.stagedSessionId);
+ rollback.stagedSessionId);
// TODO: What if session is null?
if (session != null) {
if (session.isStagedSessionApplied() || session.isStagedSessionFailed()) {
synchronized (mLock) {
- data.restoreUserDataInProgress = false;
+ rollback.restoreUserDataInProgress = false;
}
- saveRollbackData(data);
+ saveRollback(rollback);
}
}
}
@@ -688,19 +679,19 @@
VersionedPackage installedVersion = getInstalledPackageVersion(packageName);
synchronized (mLock) {
- Iterator<RollbackData> iter = mRollbacks.iterator();
+ Iterator<Rollback> iter = mRollbacks.iterator();
while (iter.hasNext()) {
- RollbackData data = iter.next();
+ Rollback rollback = iter.next();
// TODO: Should we remove rollbacks in the ENABLING state here?
- if (data.state == RollbackData.ROLLBACK_STATE_AVAILABLE
- || data.state == RollbackData.ROLLBACK_STATE_ENABLING) {
- for (PackageRollbackInfo info : data.info.getPackages()) {
+ if (rollback.state == Rollback.ROLLBACK_STATE_AVAILABLE
+ || rollback.state == Rollback.ROLLBACK_STATE_ENABLING) {
+ for (PackageRollbackInfo info : rollback.info.getPackages()) {
if (info.getPackageName().equals(packageName)
&& !packageVersionsEqual(
info.getVersionRolledBackFrom(),
installedVersion)) {
iter.remove();
- deleteRollback(data);
+ deleteRollback(rollback);
break;
}
}
@@ -756,17 +747,18 @@
Instant now = Instant.now();
Instant oldest = null;
synchronized (mLock) {
- Iterator<RollbackData> iter = mRollbacks.iterator();
+ Iterator<Rollback> iter = mRollbacks.iterator();
while (iter.hasNext()) {
- RollbackData data = iter.next();
- if (data.state != RollbackData.ROLLBACK_STATE_AVAILABLE) {
+ Rollback rollback = iter.next();
+ if (rollback.state != Rollback.ROLLBACK_STATE_AVAILABLE) {
continue;
}
- if (!now.isBefore(data.timestamp.plusMillis(mRollbackLifetimeDurationInMillis))) {
+ if (!now.isBefore(
+ rollback.timestamp.plusMillis(mRollbackLifetimeDurationInMillis))) {
iter.remove();
- deleteRollback(data);
- } else if (oldest == null || oldest.isAfter(data.timestamp)) {
- oldest = data.timestamp;
+ deleteRollback(rollback);
+ } else if (oldest == null || oldest.isAfter(rollback.timestamp)) {
+ oldest = rollback.timestamp;
}
}
}
@@ -821,13 +813,12 @@
*
* @param installFlags information about what is being installed.
* @param newPackageCodePath path to the package about to be installed.
- * @param installedUsers the set of users for which a given package is installed.
* @param user the user that owns the install session to enable rollback on.
* @param token the distinct rollback token sent by package manager.
* @return true if enabling the rollback succeeds, false otherwise.
*/
- private boolean enableRollback(int installFlags, File newPackageCodePath,
- int[] installedUsers, @UserIdInt int user, int token) {
+ private boolean enableRollback(
+ int installFlags, File newPackageCodePath, @UserIdInt int user, int token) {
// Find the session id associated with this install.
// TODO: It would be nice if package manager or package installer told
@@ -872,38 +863,15 @@
// Check to see if this is the apk session for a staged session with
// rollback enabled.
- // TODO: This check could be made more efficient.
- RollbackData rd = null;
synchronized (mLock) {
for (int i = 0; i < mRollbacks.size(); ++i) {
- RollbackData data = mRollbacks.get(i);
- if (data.apkSessionId == parentSession.getSessionId()) {
- rd = data;
- break;
- }
- }
- }
-
- if (rd != null) {
- // This is the apk session for a staged session. We do not need to create a new rollback
- // for this session.
- PackageParser.PackageLite newPackage = null;
- try {
- newPackage = PackageParser.parsePackageLite(
- new File(packageSession.resolvedBaseCodePath), 0);
- } catch (PackageParser.PackageParserException e) {
- Slog.e(TAG, "Unable to parse new package", e);
- return false;
- }
- String packageName = newPackage.packageName;
- for (PackageRollbackInfo info : rd.info.getPackages()) {
- if (info.getPackageName().equals(packageName)) {
- info.getInstalledUsers().addAll(IntArray.wrap(installedUsers));
+ Rollback rollback = mRollbacks.get(i);
+ if (rollback.apkSessionId == parentSession.getSessionId()) {
+ // This is the apk session for a staged session with rollback enabled. We do not
+ // need to create a new rollback for this session.
return true;
}
}
- Slog.e(TAG, "Unable to find package in apk session");
- return false;
}
NewRollback newRollback;
@@ -919,7 +887,7 @@
}
newRollback.addToken(token);
- return enableRollbackForPackageSession(newRollback.data, packageSession, installedUsers);
+ return enableRollbackForPackageSession(newRollback.rollback, packageSession);
}
/**
@@ -929,8 +897,8 @@
*
* @return true on success, false on failure.
*/
- private boolean enableRollbackForPackageSession(RollbackData data,
- PackageInstaller.SessionInfo session, @NonNull int[] installedUsers) {
+ private boolean enableRollbackForPackageSession(Rollback rollback,
+ PackageInstaller.SessionInfo session) {
// TODO: Don't attempt to enable rollback for split installs.
final int installFlags = session.installFlags;
if ((installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) == 0) {
@@ -988,15 +956,14 @@
PackageRollbackInfo packageRollbackInfo = new PackageRollbackInfo(
newVersion, installedVersion,
new IntArray() /* pendingBackups */, new ArrayList<>() /* pendingRestores */,
- isApex, IntArray.wrap(installedUsers),
- new SparseLongArray() /* ceSnapshotInodes */);
+ isApex, new IntArray(), new SparseLongArray() /* ceSnapshotInodes */);
try {
ApplicationInfo appInfo = pkgInfo.applicationInfo;
- RollbackStore.backupPackageCodePath(data, packageName, appInfo.sourceDir);
+ RollbackStore.backupPackageCodePath(rollback, packageName, appInfo.sourceDir);
if (!ArrayUtils.isEmpty(appInfo.splitSourceDirs)) {
for (String sourceDir : appInfo.splitSourceDirs) {
- RollbackStore.backupPackageCodePath(data, packageName, sourceDir);
+ RollbackStore.backupPackageCodePath(rollback, packageName, sourceDir);
}
}
} catch (IOException e) {
@@ -1005,7 +972,7 @@
}
synchronized (mLock) {
- data.info.getPackages().add(packageRollbackInfo);
+ rollback.info.getPackages().add(packageRollbackInfo);
}
return true;
}
@@ -1019,7 +986,7 @@
}
getHandler().post(() -> {
- snapshotUserDataInternal(packageName);
+ snapshotUserDataInternal(packageName, userIds);
restoreUserDataInternal(packageName, userIds, appId, ceDataInode, seInfo, token);
final PackageManagerInternal pmi = LocalServices.getService(
PackageManagerInternal.class);
@@ -1027,19 +994,20 @@
});
}
- private void snapshotUserDataInternal(String packageName) {
+ private void snapshotUserDataInternal(String packageName, int[] userIds) {
synchronized (mLock) {
// staged installs
for (int i = 0; i < mRollbacks.size(); i++) {
- RollbackData data = mRollbacks.get(i);
- if (data.state != RollbackData.ROLLBACK_STATE_ENABLING) {
+ Rollback rollback = mRollbacks.get(i);
+ if (rollback.state != Rollback.ROLLBACK_STATE_ENABLING) {
continue;
}
- for (PackageRollbackInfo info : data.info.getPackages()) {
+ for (PackageRollbackInfo info : rollback.info.getPackages()) {
if (info.getPackageName().equals(packageName)) {
- mAppDataRollbackHelper.snapshotAppData(data.info.getRollbackId(), info);
- saveRollbackData(data);
+ mAppDataRollbackHelper.snapshotAppData(
+ rollback.info.getRollbackId(), info, userIds);
+ saveRollback(rollback);
break;
}
}
@@ -1047,11 +1015,11 @@
// non-staged installs
PackageRollbackInfo info;
for (NewRollback rollback : mNewRollbacks) {
- info = getPackageRollbackInfo(rollback.data, packageName);
+ info = getPackageRollbackInfo(rollback.rollback, packageName);
if (info != null) {
- mAppDataRollbackHelper.snapshotAppData(rollback.data.info.getRollbackId(),
- info);
- saveRollbackData(rollback.data);
+ mAppDataRollbackHelper.snapshotAppData(
+ rollback.rollback.info.getRollbackId(), info, userIds);
+ saveRollback(rollback.rollback);
}
}
}
@@ -1060,31 +1028,31 @@
private void restoreUserDataInternal(String packageName, int[] userIds, int appId,
long ceDataInode, String seInfo, int token) {
PackageRollbackInfo info = null;
- RollbackData rollbackData = null;
+ Rollback rollback = null;
synchronized (mLock) {
for (int i = 0; i < mRollbacks.size(); ++i) {
- RollbackData data = mRollbacks.get(i);
- if (data.restoreUserDataInProgress) {
- info = getPackageRollbackInfo(data, packageName);
+ Rollback candidate = mRollbacks.get(i);
+ if (candidate.restoreUserDataInProgress) {
+ info = getPackageRollbackInfo(candidate, packageName);
if (info != null) {
- rollbackData = data;
+ rollback = candidate;
break;
}
}
}
}
- if (rollbackData == null) {
+ if (rollback == null) {
return;
}
for (int userId : userIds) {
- final boolean changedRollbackData = mAppDataRollbackHelper.restoreAppData(
- rollbackData.info.getRollbackId(), info, userId, appId, seInfo);
+ final boolean changedRollback = mAppDataRollbackHelper.restoreAppData(
+ rollback.info.getRollbackId(), info, userId, appId, seInfo);
// We've updated metadata about this rollback, so save it to flash.
- if (changedRollbackData) {
- saveRollbackData(rollbackData);
+ if (changedRollback) {
+ saveRollback(rollback);
}
}
}
@@ -1114,8 +1082,7 @@
}
if (!session.isMultiPackage()) {
- if (!enableRollbackForPackageSession(newRollback.data, session,
- new int[0])) {
+ if (!enableRollbackForPackageSession(newRollback.rollback, session)) {
Slog.e(TAG, "Unable to enable rollback for session: " + sessionId);
result.offer(false);
return;
@@ -1129,8 +1096,7 @@
result.offer(false);
return;
}
- if (!enableRollbackForPackageSession(newRollback.data, childSession,
- new int[0])) {
+ if (!enableRollbackForPackageSession(newRollback.rollback, childSession)) {
Slog.e(TAG, "Unable to enable rollback for session: " + sessionId);
result.offer(false);
return;
@@ -1155,20 +1121,20 @@
throw new SecurityException("notifyStagedApkSession may only be called by the system.");
}
getHandler().post(() -> {
- RollbackData rd = null;
+ Rollback rollback = null;
synchronized (mLock) {
for (int i = 0; i < mRollbacks.size(); ++i) {
- RollbackData data = mRollbacks.get(i);
- if (data.stagedSessionId == originalSessionId) {
- data.apkSessionId = apkSessionId;
- rd = data;
+ Rollback candidate = mRollbacks.get(i);
+ if (candidate.stagedSessionId == originalSessionId) {
+ candidate.apkSessionId = apkSessionId;
+ rollback = candidate;
break;
}
}
}
- if (rd != null) {
- saveRollbackData(rd);
+ if (rollback != null) {
+ saveRollback(rollback);
}
});
}
@@ -1278,7 +1244,7 @@
}
if (newRollback != null) {
- RollbackData rollback = completeEnableRollback(newRollback, success);
+ Rollback rollback = completeEnableRollback(newRollback, success);
if (rollback != null && !rollback.isStaged()) {
makeRollbackAvailable(rollback);
}
@@ -1291,32 +1257,32 @@
* This should be called after rollback has been enabled for all packages
* in the rollback. It does not make the rollback available yet.
*
- * @return the rollback data for a successfully enable-completed rollback,
+ * @return the Rollback instance for a successfully enable-completed rollback,
* or null on error.
*/
- private RollbackData completeEnableRollback(NewRollback newRollback, boolean success) {
- RollbackData data = newRollback.data;
+ private Rollback completeEnableRollback(NewRollback newRollback, boolean success) {
+ Rollback rollback = newRollback.rollback;
if (!success) {
// The install session was aborted, clean up the pending install.
- deleteRollback(data);
+ deleteRollback(rollback);
return null;
}
if (newRollback.isCancelled) {
Slog.e(TAG, "Rollback has been cancelled by PackageManager");
- deleteRollback(data);
+ deleteRollback(rollback);
return null;
}
- // It's safe to access data.info outside a synchronized block because
+ // It's safe to access rollback.info outside a synchronized block because
// this is running on the handler thread and all changes to the
- // data.info occur on the handler thread.
- if (data.info.getPackages().size() != newRollback.packageSessionIds.length) {
+ // rollback.info occur on the handler thread.
+ if (rollback.info.getPackages().size() != newRollback.packageSessionIds.length) {
Slog.e(TAG, "Failed to enable rollback for all packages in session.");
- deleteRollback(data);
+ deleteRollback(rollback);
return null;
}
- saveRollbackData(data);
+ saveRollback(rollback);
synchronized (mLock) {
// Note: There is a small window of time between when
// the session has been committed by the package
@@ -1324,25 +1290,25 @@
// here. Presumably the window is small enough that
// nobody will want to roll back the newly installed
// package before we make the rollback available.
- // TODO: We'll lose the rollback data if the
+ // TODO: We'll lose the rollback if the
// device reboots between when the session is
// committed and this point. Revisit this after
// adding support for rollback of staged installs.
- mRollbacks.add(data);
+ mRollbacks.add(rollback);
}
- return data;
+ return rollback;
}
- private void makeRollbackAvailable(RollbackData data) {
+ private void makeRollbackAvailable(Rollback rollback) {
// TODO: What if the rollback has since been expired, for example due
// to a new package being installed. Won't this revive an expired
// rollback? Consider adding a ROLLBACK_STATE_EXPIRED to address this.
synchronized (mLock) {
- data.state = RollbackData.ROLLBACK_STATE_AVAILABLE;
- data.timestamp = Instant.now();
+ rollback.state = Rollback.ROLLBACK_STATE_AVAILABLE;
+ rollback.timestamp = Instant.now();
}
- saveRollbackData(data);
+ saveRollback(rollback);
// TODO(zezeozue): Provide API to explicitly start observing instead
// of doing this for all rollbacks. If we do this for all rollbacks,
@@ -1350,8 +1316,8 @@
// After enabling and commiting any rollback, observe packages and
// prepare to rollback if packages crashes too frequently.
List<String> packages = new ArrayList<>();
- for (int i = 0; i < data.info.getPackages().size(); i++) {
- packages.add(data.info.getPackages().get(i).getPackageName());
+ for (int i = 0; i < rollback.info.getPackages().size(); i++) {
+ packages.add(rollback.info.getPackages().get(i).getPackageName());
}
mPackageHealthObserver.startObservingHealth(packages,
mRollbackLifetimeDurationInMillis);
@@ -1359,15 +1325,14 @@
}
/*
- * Returns the RollbackData, if any, for a rollback with the given
- * rollbackId.
+ * Returns the rollback with the given rollbackId, if any.
*/
- private RollbackData getRollbackForId(int rollbackId) {
+ private Rollback getRollbackForId(int rollbackId) {
synchronized (mLock) {
for (int i = 0; i < mRollbacks.size(); ++i) {
- RollbackData data = mRollbacks.get(i);
- if (data.info.getRollbackId() == rollbackId) {
- return data;
+ Rollback rollback = mRollbacks.get(i);
+ if (rollback.info.getRollbackId() == rollbackId) {
+ return rollback;
}
}
}
@@ -1377,11 +1342,11 @@
/**
* Returns the {@code PackageRollbackInfo} associated with {@code packageName} from
- * a specified {@code RollbackData}.
+ * a specified {@code Rollback}.
*/
- private static PackageRollbackInfo getPackageRollbackInfo(RollbackData data,
+ private static PackageRollbackInfo getPackageRollbackInfo(Rollback rollback,
String packageName) {
- for (PackageRollbackInfo info : data.info.getPackages()) {
+ for (PackageRollbackInfo info : rollback.info.getPackages()) {
if (info.getPackageName().equals(packageName)) {
return info;
}
@@ -1405,30 +1370,30 @@
throw new IllegalStateException("Failed to allocate rollback ID");
}
- private void deleteRollback(RollbackData rollbackData) {
- for (PackageRollbackInfo info : rollbackData.info.getPackages()) {
- IntArray installedUsers = info.getInstalledUsers();
- for (int i = 0; i < installedUsers.size(); i++) {
- int userId = installedUsers.get(i);
- mAppDataRollbackHelper.destroyAppDataSnapshot(rollbackData.info.getRollbackId(),
+ private void deleteRollback(Rollback rollback) {
+ for (PackageRollbackInfo info : rollback.info.getPackages()) {
+ IntArray snapshottedUsers = info.getSnapshottedUsers();
+ for (int i = 0; i < snapshottedUsers.size(); i++) {
+ int userId = snapshottedUsers.get(i);
+ mAppDataRollbackHelper.destroyAppDataSnapshot(rollback.info.getRollbackId(),
info, userId);
}
}
- mRollbackStore.deleteRollbackData(rollbackData);
+ mRollbackStore.deleteRollback(rollback);
}
/**
- * Saves rollback data, swallowing any IOExceptions.
+ * Saves a rollback, swallowing any IOExceptions.
* For those times when it's not obvious what to do about the IOException.
* TODO: Double check we can't do a better job handling the IOException in
* a cases where this method is called.
*/
- private void saveRollbackData(RollbackData rollbackData) {
+ private void saveRollback(Rollback rollback) {
try {
- mRollbackStore.saveRollbackData(rollbackData);
+ mRollbackStore.saveRollback(rollback);
} catch (IOException ioe) {
- Slog.e(TAG, "Unable to save rollback info for: "
- + rollbackData.info.getRollbackId(), ioe);
+ Slog.e(TAG, "Unable to save rollback for: "
+ + rollback.info.getRollbackId(), ioe);
}
}
@@ -1436,14 +1401,14 @@
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
synchronized (mLock) {
- for (RollbackData data : mRollbacks) {
- RollbackInfo info = data.info;
+ for (Rollback rollback : mRollbacks) {
+ RollbackInfo info = rollback.info;
ipw.println(info.getRollbackId() + ":");
ipw.increaseIndent();
- ipw.println("-state: " + data.getStateAsString());
- ipw.println("-timestamp: " + data.timestamp);
- if (data.stagedSessionId != -1) {
- ipw.println("-stagedSessionId: " + data.stagedSessionId);
+ ipw.println("-state: " + rollback.getStateAsString());
+ ipw.println("-timestamp: " + rollback.timestamp);
+ if (rollback.stagedSessionId != -1) {
+ ipw.println("-stagedSessionId: " + rollback.stagedSessionId);
}
ipw.println("-packages:");
ipw.increaseIndent();
@@ -1453,7 +1418,7 @@
+ " -> " + pkg.getVersionRolledBackTo().getLongVersionCode());
}
ipw.decreaseIndent();
- if (data.state == RollbackData.ROLLBACK_STATE_COMMITTED) {
+ if (rollback.state == Rollback.ROLLBACK_STATE_COMMITTED) {
ipw.println("-causePackages:");
ipw.increaseIndent();
for (VersionedPackage cPkg : info.getCausePackages()) {
@@ -1479,7 +1444,7 @@
}
private static class NewRollback {
- public final RollbackData data;
+ public final Rollback rollback;
/**
* This array holds all of the rollback tokens associated with package sessions included
@@ -1497,9 +1462,9 @@
public final int[] packageSessionIds;
/**
- * Flag to determine whether the RollbackData has been cancelled.
+ * Flag to determine whether the rollback has been cancelled.
*
- * <p>RollbackData could be invalidated and cancelled if RollbackManager receives
+ * <p>Rollback could be invalidated and cancelled if RollbackManager receives
* {@link Intent#ACTION_CANCEL_ENABLE_ROLLBACK} from {@link PackageManager}.
*
* <p>The main underlying assumption here is that if enabling the rollback times out, then
@@ -1509,8 +1474,8 @@
*/
public boolean isCancelled = false;
- NewRollback(RollbackData data, int[] packageSessionIds) {
- this.data = data;
+ NewRollback(Rollback rollback, int[] packageSessionIds) {
+ this.rollback = rollback;
this.packageSessionIds = packageSessionIds;
}
@@ -1525,13 +1490,13 @@
NewRollback createNewRollbackLocked(PackageInstaller.SessionInfo parentSession) {
int rollbackId = allocateRollbackIdLocked();
- final RollbackData data;
+ final Rollback rollback;
int parentSessionId = parentSession.getSessionId();
if (parentSession.isStaged()) {
- data = mRollbackStore.createStagedRollback(rollbackId, parentSessionId);
+ rollback = mRollbackStore.createStagedRollback(rollbackId, parentSessionId);
} else {
- data = mRollbackStore.createNonStagedRollback(rollbackId);
+ rollback = mRollbackStore.createNonStagedRollback(rollbackId);
}
int[] packageSessionIds;
@@ -1541,7 +1506,7 @@
packageSessionIds = new int[]{parentSessionId};
}
- return new NewRollback(data, packageSessionIds);
+ return new NewRollback(rollback, packageSessionIds);
}
/**
@@ -1552,10 +1517,10 @@
NewRollback getNewRollbackForPackageSessionLocked(int packageSessionId) {
// We expect mNewRollbacks to be a very small list; linear search
// should be plenty fast.
- for (NewRollback newRollbackData : mNewRollbacks) {
- for (int id : newRollbackData.packageSessionIds) {
+ for (NewRollback newRollback: mNewRollbacks) {
+ for (int id : newRollback.packageSessionIds) {
if (id == packageSessionId) {
- return newRollbackData;
+ return newRollback;
}
}
}
diff --git a/services/core/java/com/android/server/rollback/RollbackStore.java b/services/core/java/com/android/server/rollback/RollbackStore.java
index 1c36dc7..b2448f6 100644
--- a/services/core/java/com/android/server/rollback/RollbackStore.java
+++ b/services/core/java/com/android/server/rollback/RollbackStore.java
@@ -16,8 +16,8 @@
package com.android.server.rollback;
-import static com.android.server.rollback.RollbackData.rollbackStateFromString;
-import static com.android.server.rollback.RollbackData.rollbackStateToString;
+import static com.android.server.rollback.Rollback.rollbackStateFromString;
+import static com.android.server.rollback.Rollback.rollbackStateToString;
import android.annotation.NonNull;
import android.content.pm.VersionedPackage;
@@ -73,17 +73,17 @@
}
/**
- * Reads the rollback data from persistent storage.
+ * Reads the rollbacks from persistent storage.
*/
- List<RollbackData> loadAllRollbackData() {
- List<RollbackData> rollbacks = new ArrayList<>();
+ List<Rollback> loadRollbacks() {
+ List<Rollback> rollbacks = new ArrayList<>();
mRollbackDataDir.mkdirs();
for (File rollbackDir : mRollbackDataDir.listFiles()) {
if (rollbackDir.isDirectory()) {
try {
- rollbacks.add(loadRollbackData(rollbackDir));
+ rollbacks.add(loadRollback(rollbackDir));
} catch (IOException e) {
- Slog.e(TAG, "Unable to read rollback data at " + rollbackDir, e);
+ Slog.e(TAG, "Unable to read rollback at " + rollbackDir, e);
removeFile(rollbackDir);
}
}
@@ -191,21 +191,21 @@
}
/**
- * Creates a new RollbackData instance for a non-staged rollback with
+ * Creates a new Rollback instance for a non-staged rollback with
* backupDir assigned.
*/
- RollbackData createNonStagedRollback(int rollbackId) {
+ Rollback createNonStagedRollback(int rollbackId) {
File backupDir = new File(mRollbackDataDir, Integer.toString(rollbackId));
- return new RollbackData(rollbackId, backupDir, -1);
+ return new Rollback(rollbackId, backupDir, -1);
}
/**
- * Creates a new RollbackData instance for a staged rollback with
+ * Creates a new Rollback instance for a staged rollback with
* backupDir assigned.
*/
- RollbackData createStagedRollback(int rollbackId, int stagedSessionId) {
+ Rollback createStagedRollback(int rollbackId, int stagedSessionId) {
File backupDir = new File(mRollbackDataDir, Integer.toString(rollbackId));
- return new RollbackData(rollbackId, backupDir, stagedSessionId);
+ return new Rollback(rollbackId, backupDir, stagedSessionId);
}
/**
@@ -213,10 +213,10 @@
* For packages containing splits, this method should be called for each
* of the package's split apks in addition to the base apk.
*/
- static void backupPackageCodePath(RollbackData data, String packageName, String codePath)
+ static void backupPackageCodePath(Rollback rollback, String packageName, String codePath)
throws IOException {
File sourceFile = new File(codePath);
- File targetDir = new File(data.backupDir, packageName);
+ File targetDir = new File(rollback.backupDir, packageName);
targetDir.mkdirs();
File targetFile = new File(targetDir, sourceFile.getName());
@@ -228,8 +228,8 @@
* Returns the apk or apex files backed up for the given package.
* Includes the base apk and any splits. Returns null if none found.
*/
- static File[] getPackageCodePaths(RollbackData data, String packageName) {
- File targetDir = new File(data.backupDir, packageName);
+ static File[] getPackageCodePaths(Rollback rollback, String packageName) {
+ File targetDir = new File(rollback.backupDir, packageName);
File[] files = targetDir.listFiles();
if (files == null || files.length == 0) {
return null;
@@ -241,27 +241,27 @@
* Deletes all backed up apks and apex files associated with the given
* rollback.
*/
- static void deletePackageCodePaths(RollbackData data) {
- for (PackageRollbackInfo info : data.info.getPackages()) {
- File targetDir = new File(data.backupDir, info.getPackageName());
+ static void deletePackageCodePaths(Rollback rollback) {
+ for (PackageRollbackInfo info : rollback.info.getPackages()) {
+ File targetDir = new File(rollback.backupDir, info.getPackageName());
removeFile(targetDir);
}
}
/**
- * Saves the rollback data to persistent storage.
+ * Saves the given rollback to persistent storage.
*/
- void saveRollbackData(RollbackData data) throws IOException {
+ void saveRollback(Rollback rollback) throws IOException {
try {
JSONObject dataJson = new JSONObject();
- dataJson.put("info", rollbackInfoToJson(data.info));
- dataJson.put("timestamp", data.timestamp.toString());
- dataJson.put("stagedSessionId", data.stagedSessionId);
- dataJson.put("state", rollbackStateToString(data.state));
- dataJson.put("apkSessionId", data.apkSessionId);
- dataJson.put("restoreUserDataInProgress", data.restoreUserDataInProgress);
+ dataJson.put("info", rollbackInfoToJson(rollback.info));
+ dataJson.put("timestamp", rollback.timestamp.toString());
+ dataJson.put("stagedSessionId", rollback.stagedSessionId);
+ dataJson.put("state", rollbackStateToString(rollback.state));
+ dataJson.put("apkSessionId", rollback.apkSessionId);
+ dataJson.put("restoreUserDataInProgress", rollback.restoreUserDataInProgress);
- PrintWriter pw = new PrintWriter(new File(data.backupDir, "rollback.json"));
+ PrintWriter pw = new PrintWriter(new File(rollback.backupDir, "rollback.json"));
pw.println(dataJson.toString());
pw.close();
} catch (JSONException e) {
@@ -270,23 +270,23 @@
}
/**
- * Removes all persistant storage associated with the given rollback data.
+ * Removes all persistent storage associated with the given rollback.
*/
- void deleteRollbackData(RollbackData data) {
- removeFile(data.backupDir);
+ void deleteRollback(Rollback rollback) {
+ removeFile(rollback.backupDir);
}
/**
* Reads the metadata for a rollback from the given directory.
* @throws IOException in case of error reading the data.
*/
- private static RollbackData loadRollbackData(File backupDir) throws IOException {
+ private static Rollback loadRollback(File backupDir) throws IOException {
try {
File rollbackJsonFile = new File(backupDir, "rollback.json");
JSONObject dataJson = new JSONObject(
IoUtils.readFileAsString(rollbackJsonFile.getAbsolutePath()));
- return new RollbackData(
+ return new Rollback(
rollbackInfoFromJson(dataJson.getJSONObject("info")),
backupDir,
Instant.parse(dataJson.getString("timestamp")),
@@ -319,13 +319,14 @@
IntArray pendingBackups = info.getPendingBackups();
List<RestoreInfo> pendingRestores = info.getPendingRestores();
- IntArray installedUsers = info.getInstalledUsers();
+ IntArray snapshottedUsers = info.getSnapshottedUsers();
json.put("pendingBackups", convertToJsonArray(pendingBackups));
json.put("pendingRestores", convertToJsonArray(pendingRestores));
json.put("isApex", info.isApex());
- json.put("installedUsers", convertToJsonArray(installedUsers));
+ // Field is named 'installedUsers' for legacy reasons.
+ json.put("installedUsers", convertToJsonArray(snapshottedUsers));
json.put("ceSnapshotInodes", ceSnapshotInodesToJson(info.getCeSnapshotInodes()));
return json;
@@ -345,12 +346,13 @@
final boolean isApex = json.getBoolean("isApex");
- final IntArray installedUsers = convertToIntArray(json.getJSONArray("installedUsers"));
+ // Field is named 'installedUsers' for legacy reasons.
+ final IntArray snapshottedUsers = convertToIntArray(json.getJSONArray("installedUsers"));
final SparseLongArray ceSnapshotInodes = ceSnapshotInodesFromJson(
json.getJSONArray("ceSnapshotInodes"));
return new PackageRollbackInfo(versionRolledBackFrom, versionRolledBackTo,
- pendingBackups, pendingRestores, isApex, installedUsers, ceSnapshotInodes);
+ pendingBackups, pendingRestores, isApex, snapshottedUsers, ceSnapshotInodes);
}
private static JSONArray versionedPackagesToJson(List<VersionedPackage> packages)
diff --git a/services/core/java/com/android/server/security/KeyChainSystemService.java b/services/core/java/com/android/server/security/KeyChainSystemService.java
index 2f681a3..3c06d0e 100644
--- a/services/core/java/com/android/server/security/KeyChainSystemService.java
+++ b/services/core/java/com/android/server/security/KeyChainSystemService.java
@@ -27,7 +27,7 @@
import android.security.IKeyChainService;
import android.util.Slog;
-import com.android.server.DeviceIdleController;
+import com.android.server.DeviceIdleInternal;
import com.android.server.LocalServices;
import com.android.server.SystemService;
@@ -99,8 +99,8 @@
}
final String packageName = intent.getComponent().getPackageName();
- final DeviceIdleController.LocalService idleController =
- LocalServices.getService(DeviceIdleController.LocalService.class);
+ final DeviceIdleInternal idleController =
+ LocalServices.getService(DeviceIdleInternal.class);
idleController.addPowerSaveTempWhitelistApp(Process.myUid(), packageName,
KEYCHAIN_IDLE_WHITELIST_DURATION_MS, user.getIdentifier(), false, "keychain");
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index d67048f..8897eca 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -610,11 +610,12 @@
@Override
public void showBiometricDialog(Bundle bundle, IBiometricServiceReceiverInternal receiver,
- int type, boolean requireConfirmation, int userId) {
+ int type, boolean requireConfirmation, int userId, String opPackageName) {
enforceBiometricDialog();
if (mBar != null) {
try {
- mBar.showBiometricDialog(bundle, receiver, type, requireConfirmation, userId);
+ mBar.showBiometricDialog(bundle, receiver, type, requireConfirmation, userId,
+ opPackageName);
} catch (RemoteException ex) {
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java
index f1cd721..5a0dfd0 100644
--- a/services/core/java/com/android/server/wm/ActivityDisplay.java
+++ b/services/core/java/com/android/server/wm/ActivityDisplay.java
@@ -41,6 +41,7 @@
import static com.android.server.am.ActivityDisplayProto.SINGLE_TASK_INSTANCE;
import static com.android.server.am.ActivityDisplayProto.STACKS;
import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
+import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE;
import static com.android.server.wm.ActivityStackSupervisor.TAG_TASKS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STACK;
@@ -173,18 +174,10 @@
mService = root.mService;
mDisplayId = display.getDisplayId();
mDisplay = display;
- mDisplayContent = createDisplayContent();
+ mDisplayContent = mService.mWindowManager.mRoot.createDisplayContent(mDisplay, this);
mDisplayContent.reconfigureDisplayLocked();
- updateBounds();
- }
-
- protected DisplayContent createDisplayContent() {
- return mService.mWindowManager.mRoot.createDisplayContent(mDisplay, this);
- }
-
- private void updateBounds() {
- mDisplay.getRealSize(mTmpDisplaySize);
- setBounds(0, 0, mTmpDisplaySize.x, mTmpDisplaySize.y);
+ onRequestedOverrideConfigurationChanged(
+ mDisplayContent.getRequestedOverrideConfiguration());
}
void onDisplayChanged() {
@@ -200,7 +193,8 @@
}
}
- updateBounds();
+ mDisplay.getRealSize(mTmpDisplaySize);
+ setBounds(0, 0, mTmpDisplaySize.x, mTmpDisplaySize.y);
if (mDisplayContent != null) {
mDisplayContent.updateDisplayInfo();
mService.mWindowManager.requestTraversal();
@@ -1541,6 +1535,17 @@
return mSingleTaskInstance;
}
+ @VisibleForTesting
+ void removeAllTasks() {
+ for (int i = getChildCount() - 1; i >= 0; --i) {
+ final ActivityStack stack = getChildAt(i);
+ final ArrayList<TaskRecord> tasks = stack.getAllTasks();
+ for (int j = tasks.size() - 1; j >= 0; --j) {
+ stack.removeTask(tasks.get(j), "removeAllTasks", REMOVE_TASK_MODE_DESTROYING);
+ }
+ }
+ }
+
public void dump(PrintWriter pw, String prefix) {
pw.println(prefix + "displayId=" + mDisplayId + " stacks=" + mStacks.size()
+ (mSingleTaskInstance ? " mSingleTaskInstance" : ""));
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 31e8bbdab..2269537 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -121,6 +121,7 @@
import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE;
import static com.android.server.wm.ActivityStack.STOP_TIMEOUT_MSG;
import static com.android.server.wm.ActivityStackSupervisor.PAUSE_IMMEDIATELY;
+import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONTAINERS;
@@ -1372,16 +1373,17 @@
return stack != null ? stack.getDisplay() : null;
}
- boolean changeWindowTranslucency(boolean toOpaque) {
- if (fullscreen == toOpaque) {
- return false;
+ boolean setOccludesParent(boolean occludesParent) {
+ final boolean changed = mAppWindowToken.setOccludesParent(occludesParent);
+ if (changed) {
+ if (!occludesParent) {
+ getActivityStack().convertActivityToTranslucent(this);
+ }
+ // Keep track of the number of fullscreen activities in this task.
+ task.numFullscreen += occludesParent ? +1 : -1;
+ mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
}
-
- // Keep track of the number of fullscreen activities in this task.
- task.numFullscreen += toOpaque ? +1 : -1;
-
- fullscreen = toOpaque;
- return true;
+ return changed;
}
void takeFromHistory() {
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 12eab50..daf3286 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -2492,7 +2492,7 @@
mHandler.removeMessages(TRANSLUCENT_TIMEOUT_MSG);
if (waitingActivity != null) {
- mWindowManager.setWindowOpaque(waitingActivity.appToken, false);
+ mWindowManager.setWindowOpaqueLocked(waitingActivity.appToken, false);
if (waitingActivity.attachedToProcess()) {
try {
waitingActivity.app.getThread().scheduleTranslucentConversionComplete(
@@ -2813,7 +2813,7 @@
// Launching this app's activity, make sure the app is no longer
// considered stopped.
try {
- AppGlobals.getPackageManager().setPackageStoppedState(
+ mService.getPackageManager().setPackageStoppedState(
next.packageName, false, next.mUserId); /* TODO: Verify if correct userid */
} catch (RemoteException e1) {
} catch (IllegalArgumentException e) {
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 1c56a10..22f72a4 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -250,7 +250,7 @@
RecentTasks mRecentTasks;
/** Helper class to abstract out logic for fetching the set of currently running tasks */
- RunningTasks mRunningTasks;
+ private RunningTasks mRunningTasks;
final ActivityStackSupervisorHandler mHandler;
final Looper mLooper;
@@ -444,7 +444,7 @@
}
mInitialized = true;
- mRunningTasks = createRunningTasks();
+ setRunningTasks(new RunningTasks());
mActivityMetricsLogger = new ActivityMetricsLogger(this, mService.mContext,
mHandler.getLooper());
@@ -485,13 +485,20 @@
}
void setRecentTasks(RecentTasks recentTasks) {
+ if (mRecentTasks != null) {
+ mRecentTasks.unregisterCallback(this);
+ }
mRecentTasks = recentTasks;
mRecentTasks.registerCallback(this);
}
@VisibleForTesting
- RunningTasks createRunningTasks() {
- return new RunningTasks();
+ void setRunningTasks(RunningTasks runningTasks) {
+ mRunningTasks = runningTasks;
+ }
+
+ RunningTasks getRunningTasks() {
+ return mRunningTasks;
}
/**
@@ -2735,7 +2742,7 @@
mWindowManager.deferSurfaceLayout();
try {
if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
- mWindowManager.setDockedStackCreateState(
+ mWindowManager.setDockedStackCreateStateLocked(
activityOptions.getSplitScreenCreateMode(), null /* initialBounds */);
// Defer updating the stack in which recents is until the app transition is done, to
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index a3ab27e..a7b6e0f 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -43,7 +43,6 @@
import static android.content.pm.ConfigurationInfo.GL_ES_VERSION_UNDEFINED;
import static android.content.pm.PackageManager.FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS;
import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT;
-import static android.content.pm.PackageManager.FEATURE_PC;
import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.content.res.Configuration.UI_MODE_TYPE_TELEVISION;
@@ -211,7 +210,7 @@
import android.sysprop.DisplayProperties;
import android.telecom.TelecomManager;
import android.text.TextUtils;
-import android.text.format.Time;
+import android.text.format.TimeMigrationUtils;
import android.util.ArrayMap;
import android.util.EventLog;
import android.util.Log;
@@ -361,7 +360,7 @@
/* Global service lock used by the package the owns this service. */
final WindowManagerGlobalLock mGlobalLock = new WindowManagerGlobalLock();
/**
- * It is the same instance as {@link mGlobalLock}, just declared as a type that the
+ * It is the same instance as {@link #mGlobalLock}, just declared as a type that the
* locked-region-code-injection does't recognize it. It is used to skip wrapping priority
* booster for places that are already in the scope of another booster (e.g. computing oom-adj).
*
@@ -730,7 +729,6 @@
final boolean forceRtl = Settings.Global.getInt(resolver, DEVELOPMENT_FORCE_RTL, 0) != 0;
final boolean forceResizable = Settings.Global.getInt(
resolver, DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES, 0) != 0;
- final boolean isPc = mContext.getPackageManager().hasSystemFeature(FEATURE_PC);
// Transfer any global setting for forcing RTL layout, into a System Property
DisplayProperties.debug_force_rtl(forceRtl);
@@ -761,10 +759,6 @@
mSupportsPictureInPicture = false;
mSupportsMultiDisplay = false;
}
- mWindowManager.setForceResizableTasks(mForceResizableActivities);
- mWindowManager.setSupportsPictureInPicture(mSupportsPictureInPicture);
- mWindowManager.setSupportsFreeformWindowManagement(mSupportsFreeformWindowManagement);
- mWindowManager.setIsPc(isPc);
mWindowManager.mRoot.onSettingsRetrieved();
// This happens before any activities are started, so we can change global configuration
// in-place.
@@ -821,8 +815,7 @@
new TaskChangeNotificationController(mGlobalLock, mStackSupervisor, mH);
mLockTaskController = new LockTaskController(mContext, mStackSupervisor, mH);
mActivityStartController = new ActivityStartController(this);
- mRecentTasks = createRecentTasks();
- mStackSupervisor.setRecentTasks(mRecentTasks);
+ setRecentTasks(new RecentTasks(this, mStackSupervisor));
mVrController = new VrController(mGlobalLock);
mKeyguardController = mStackSupervisor.getKeyguardController();
}
@@ -890,8 +883,10 @@
return mode == AppOpsManager.MODE_ALLOWED;
}
- protected RecentTasks createRecentTasks() {
- return new RecentTasks(this, mStackSupervisor);
+ @VisibleForTesting
+ protected void setRecentTasks(RecentTasks recentTasks) {
+ mRecentTasks = recentTasks;
+ mStackSupervisor.setRecentTasks(recentTasks);
}
RecentTasks getRecentTasks() {
@@ -1954,12 +1949,7 @@
if (r == null) {
return false;
}
- final boolean translucentChanged = r.changeWindowTranslucency(true);
- if (translucentChanged) {
- mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
- }
- mWindowManager.setAppFullscreen(token, true);
- return translucentChanged;
+ return r.setOccludesParent(true);
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -1982,13 +1972,7 @@
ActivityRecord under = task.mActivities.get(index - 1);
under.returningOptions = safeOptions != null ? safeOptions.getOptions(r) : null;
}
- final boolean translucentChanged = r.changeWindowTranslucency(false);
- if (translucentChanged) {
- r.getActivityStack().convertActivityToTranslucent(r);
- }
- mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
- mWindowManager.setAppFullscreen(token, false);
- return translucentChanged;
+ return r.setOccludesParent(false);
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -2581,7 +2565,7 @@
+ taskId + " to stack " + stackId);
}
if (stack.inSplitScreenPrimaryWindowingMode()) {
- mWindowManager.setDockedStackCreateState(
+ mWindowManager.setDockedStackCreateStateLocked(
SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT, null /* initialBounds */);
}
task.reparent(stack, toTop, REPARENT_KEEP_STACK_AT_FRONT, ANIMATE, !DEFER_RESUME,
@@ -2700,7 +2684,7 @@
+ " non-standard task " + taskId + " to split-screen windowing mode");
}
- mWindowManager.setDockedStackCreateState(createMode, initialBounds);
+ mWindowManager.setDockedStackCreateStateLocked(createMode, initialBounds);
final int windowingMode = task.getWindowingMode();
final ActivityStack stack = task.getStack();
if (toTop) {
@@ -2802,7 +2786,7 @@
try {
synchronized (mGlobalLock) {
// Cancel the recents animation synchronously (do not hold the WM lock)
- mWindowManager.cancelRecentsAnimationSynchronously(restoreHomeStackPosition
+ mWindowManager.cancelRecentsAnimation(restoreHomeStackPosition
? REORDER_MOVE_TO_ORIGINAL_POSITION
: REORDER_KEEP_IN_PLACE, "cancelRecentsAnimation/uid=" + callingUid);
}
@@ -5878,9 +5862,9 @@
tracesFile = File.createTempFile("app_slow", null, tracesDir);
StringBuilder sb = new StringBuilder();
- Time tobj = new Time();
- tobj.set(System.currentTimeMillis());
- sb.append(tobj.format("%Y-%m-%d %H:%M:%S"));
+ String timeString =
+ TimeMigrationUtils.formatMillisWithFixedFormat(System.currentTimeMillis());
+ sb.append(timeString);
sb.append(": ");
TimeUtils.formatDuration(SystemClock.uptimeMillis()-startTime, sb);
sb.append(" since ");
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 7fde6de..7e0d9a0 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -92,6 +92,7 @@
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.graphics.GraphicBuffer;
+import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Binder;
@@ -153,8 +154,11 @@
final ComponentName mActivityComponent;
final boolean mVoiceInteraction;
- /** @see WindowContainer#fillsParent() */
- private boolean mFillsParent;
+ /**
+ * The activity is opaque and fills the entire space of this task.
+ * @see WindowContainer#fillsParent()
+ */
+ private boolean mOccludesParent;
boolean mShowForAllUsers;
int mTargetSdk;
@@ -373,7 +377,7 @@
appToken = token;
mActivityComponent = activityComponent;
mVoiceInteraction = voiceInteraction;
- mFillsParent = fillsParent;
+ mOccludesParent = fillsParent;
mInputApplicationHandle = new InputApplicationHandle(appToken.asBinder());
}
@@ -2354,11 +2358,29 @@
@Override
boolean fillsParent() {
- return mFillsParent;
+ return occludesParent();
}
- void setFillsParent(boolean fillsParent) {
- mFillsParent = fillsParent;
+ /** Returns true if this activity is opaque and fills the entire space of this task. */
+ boolean occludesParent() {
+ return mOccludesParent;
+ }
+
+ boolean setOccludesParent(boolean occludesParent) {
+ final boolean changed = occludesParent != mOccludesParent;
+ mOccludesParent = occludesParent;
+ setMainWindowOpaque(occludesParent);
+ mWmService.mWindowPlacerLocked.requestTraversal();
+ return changed;
+ }
+
+ void setMainWindowOpaque(boolean isOpaque) {
+ final WindowState win = findMainWindow();
+ if (win == null) {
+ return;
+ }
+ isOpaque = isOpaque & !PixelFormat.formatHasAlpha(win.getAttrs().format);
+ win.mWinAnimator.setOpaqueLocked(isOpaque);
}
boolean containsDismissKeyguardWindow() {
@@ -3035,7 +3057,7 @@
}
pw.println(prefix + "component=" + mActivityComponent.flattenToShortString());
pw.print(prefix); pw.print("task="); pw.println(getTask());
- pw.print(prefix); pw.print(" mFillsParent="); pw.print(mFillsParent);
+ pw.print(prefix); pw.print(" mOccludesParent="); pw.print(mOccludesParent);
pw.print(" mOrientation="); pw.println(mOrientation);
pw.println(prefix + "hiddenRequested=" + hiddenRequested + " mClientHidden=" + mClientHidden
+ ((mDeferHidingClient) ? " mDeferHidingClient=" + mDeferHidingClient : "")
@@ -3152,7 +3174,7 @@
if (mThumbnail != null){
mThumbnail.writeToProto(proto, THUMBNAIL);
}
- proto.write(FILLS_PARENT, mFillsParent);
+ proto.write(FILLS_PARENT, mOccludesParent);
proto.write(APP_STOPPED, mAppStopped);
proto.write(HIDDEN_REQUESTED, hiddenRequested);
proto.write(CLIENT_HIDDEN, mClientHidden);
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 282ed42..410cc94 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -295,7 +295,8 @@
false /* forceRelayout */);
}
- private void setUserRotation(int userRotationMode, int userRotation) {
+ @VisibleForTesting
+ void setUserRotation(int userRotationMode, int userRotation) {
if (isDefaultDisplay) {
// We'll be notified via settings listener, so we don't need to update internal values.
final ContentResolver res = mContext.getContentResolver();
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettings.java b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
index 207e8ef..8507918 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowSettings.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
@@ -275,14 +275,14 @@
// This display used to be in freeform, but we don't support freeform anymore, so fall
// back to fullscreen.
if (windowingMode == WindowConfiguration.WINDOWING_MODE_FREEFORM
- && !mService.mSupportsFreeformWindowManagement) {
+ && !mService.mAtmService.mSupportsFreeformWindowManagement) {
return WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
}
// No record is present so use default windowing mode policy.
if (windowingMode == WindowConfiguration.WINDOWING_MODE_UNDEFINED) {
final boolean forceDesktopMode = mService.mForceDesktopModeOnExternalDisplays
&& displayId != Display.DEFAULT_DISPLAY;
- windowingMode = mService.mSupportsFreeformWindowManagement
+ windowingMode = mService.mAtmService.mSupportsFreeformWindowManagement
&& (mService.mIsPc || forceDesktopMode)
? WindowConfiguration.WINDOWING_MODE_FREEFORM
: WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index b1bc2197..120ce3e 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -355,7 +355,9 @@
void getTouchRegion(Rect outRegion) {
outRegion.set(mTouchRegion);
- outRegion.offset(mWindow.getFrameLw().left, mWindow.getFrameLw().top);
+ if (mWindow != null) {
+ outRegion.offset(mWindow.getFrameLw().left, mWindow.getFrameLw().top);
+ }
}
private void resetDragResizingChangeReported() {
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index 4f0332c..caa8363 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -241,7 +241,7 @@
// Fetch all the surface controls and pass them to the client to get the animation
// started. Cancel any existing recents animation running synchronously (do not hold the
// WM lock)
- mWindowManager.cancelRecentsAnimationSynchronously(REORDER_MOVE_TO_ORIGINAL_POSITION,
+ mWindowManager.cancelRecentsAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION,
"startRecentsActivity");
mWindowManager.initializeRecentsAnimation(mTargetActivityType, recentsAnimationRunner,
this, mDefaultDisplay.mDisplayId,
@@ -396,12 +396,8 @@
@Override
public void onAnimationFinished(@RecentsAnimationController.ReorderMode int reorderMode,
- boolean runSychronously, boolean sendUserLeaveHint) {
- if (runSychronously) {
- finishAnimation(reorderMode, sendUserLeaveHint);
- } else {
- mService.mH.post(() -> finishAnimation(reorderMode, sendUserLeaveHint));
- }
+ boolean sendUserLeaveHint) {
+ finishAnimation(reorderMode, sendUserLeaveHint);
}
@Override
@@ -435,8 +431,7 @@
} else {
// Just cancel directly to unleash from launcher when the next launching task is the
// current top task.
- mWindowManager.cancelRecentsAnimationSynchronously(REORDER_KEEP_IN_PLACE,
- "stackOrderChanged");
+ mWindowManager.cancelRecentsAnimation(REORDER_KEEP_IN_PLACE, "stackOrderChanged");
}
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 724a72e..8752f37 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -168,8 +168,7 @@
public interface RecentsAnimationCallbacks {
/** Callback when recents animation is finished. */
- void onAnimationFinished(@ReorderMode int reorderMode, boolean runSychronously,
- boolean sendUserLeaveHint);
+ void onAnimationFinished(@ReorderMode int reorderMode, boolean sendUserLeaveHint);
}
private final IRecentsAnimationController mController =
@@ -221,8 +220,7 @@
// prior to calling the callback
mCallbacks.onAnimationFinished(moveHomeToTop
? REORDER_MOVE_TO_TOP
- : REORDER_MOVE_TO_ORIGINAL_POSITION,
- true /* runSynchronously */, sendUserLeaveHint);
+ : REORDER_MOVE_TO_ORIGINAL_POSITION, sendUserLeaveHint);
mDisplayContent.mBoundsAnimationController.setAnimationType(FADE_IN);
} finally {
Binder.restoreCallingIdentity(token);
@@ -498,21 +496,15 @@
}
void cancelAnimation(@ReorderMode int reorderMode, String reason) {
- cancelAnimation(reorderMode, false /* runSynchronously */, false /*screenshot */, reason);
- }
-
- void cancelAnimationSynchronously(@ReorderMode int reorderMode, String reason) {
- cancelAnimation(reorderMode, true /* runSynchronously */, false /* screenshot */, reason);
+ cancelAnimation(reorderMode, false /*screenshot */, reason);
}
void cancelAnimationWithScreenshot(boolean screenshot) {
- cancelAnimation(REORDER_KEEP_IN_PLACE, true /* sync */, screenshot, "stackOrderChanged");
+ cancelAnimation(REORDER_KEEP_IN_PLACE, screenshot, "stackOrderChanged");
}
- private void cancelAnimation(@ReorderMode int reorderMode, boolean runSynchronously,
- boolean screenshot, String reason) {
- if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "cancelAnimation(): reason=" + reason
- + " runSynchronously=" + runSynchronously);
+ private void cancelAnimation(@ReorderMode int reorderMode, boolean screenshot, String reason) {
+ if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "cancelAnimation(): reason=" + reason);
synchronized (mService.getWindowManagerLock()) {
if (mCanceled) {
// We've already canceled the animation
@@ -525,16 +517,14 @@
// Screen shot previous task when next task starts transition and notify the runner.
// We will actually finish the animation once the runner calls cleanUpScreenshot().
final Task task = mPendingAnimations.get(0).mTask;
- final TaskSnapshot taskSnapshot = screenshotRecentTask(task, reorderMode,
- runSynchronously);
+ final TaskSnapshot taskSnapshot = screenshotRecentTask(task, reorderMode);
try {
mRunner.onAnimationCanceled(taskSnapshot);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to cancel recents animation", e);
}
if (taskSnapshot == null) {
- mCallbacks.onAnimationFinished(reorderMode, runSynchronously,
- false /* sendUserLeaveHint */);
+ mCallbacks.onAnimationFinished(reorderMode, false /* sendUserLeaveHint */);
}
} else {
// Otherwise, notify the runner and clean up the animation immediately
@@ -545,8 +535,7 @@
} catch (RemoteException e) {
Slog.e(TAG, "Failed to cancel recents animation", e);
}
- mCallbacks.onAnimationFinished(reorderMode, runSynchronously,
- false /* sendUserLeaveHint */);
+ mCallbacks.onAnimationFinished(reorderMode, false /* sendUserLeaveHint */);
}
}
}
@@ -592,8 +581,7 @@
return mRequestDeferCancelUntilNextTransition && mCancelDeferredWithScreenshot;
}
- TaskSnapshot screenshotRecentTask(Task task, @ReorderMode int reorderMode,
- boolean runSynchronously) {
+ TaskSnapshot screenshotRecentTask(Task task, @ReorderMode int reorderMode) {
final TaskSnapshotController snapshotController = mService.mTaskSnapshotController;
final ArraySet<Task> tasks = Sets.newArraySet(task);
snapshotController.snapshotTasks(tasks);
@@ -613,8 +601,7 @@
if (DEBUG_RECENTS_ANIMATIONS) {
Slog.d(TAG, "mRecentScreenshotAnimator finish");
}
- mCallbacks.onAnimationFinished(reorderMode, runSynchronously,
- false /* sendUserLeaveHint */);
+ mCallbacks.onAnimationFinished(reorderMode, false /* sendUserLeaveHint */);
}, mService);
mRecentScreenshotAnimator.transferAnimation(task.mSurfaceAnimator);
return taskSnapshot;
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index 66d42db..3401de6 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -227,15 +227,10 @@
mStackSupervisor.mRootActivityContainer = this;
}
- @VisibleForTesting
- void setWindowContainer(RootWindowContainer container) {
- mRootWindowContainer = container;
- mRootWindowContainer.setRootActivityContainer(this);
- }
-
void setWindowManager(WindowManagerService wm) {
mWindowManager = wm;
- setWindowContainer(mWindowManager.mRoot);
+ mRootWindowContainer = mWindowManager.mRoot;
+ mRootWindowContainer.setRootActivityContainer(this);
mDisplayManager = mService.mContext.getSystemService(DisplayManager.class);
mDisplayManager.registerDisplayListener(this, mService.mUiHandler);
mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
@@ -2266,7 +2261,7 @@
@WindowConfiguration.ActivityType int ignoreActivityType,
@WindowConfiguration.WindowingMode int ignoreWindowingMode, int callingUid,
boolean allowed) {
- mStackSupervisor.mRunningTasks.getTasks(maxNum, list, ignoreActivityType,
+ mStackSupervisor.getRunningTasks().getTasks(maxNum, list, ignoreActivityType,
ignoreWindowingMode, mActivityDisplays, callingUid, allowed);
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index fd86faa..3a2eb57 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -380,7 +380,7 @@
boolean isResizeable() {
return ActivityInfo.isResizeableMode(mResizeMode) || mSupportsPictureInPicture
- || mWmService.mForceResizableTasks;
+ || mWmService.mAtmService.mForceResizableActivities;
}
/**
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 79367a0..cc2112e 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -1666,7 +1666,7 @@
* default bounds.
*/
Rect getPictureInPictureBounds(float aspectRatio, Rect stackBounds) {
- if (!mWmService.mSupportsPictureInPicture) {
+ if (!mWmService.mAtmService.mSupportsPictureInPicture) {
return null;
}
@@ -1762,7 +1762,7 @@
* Sets the current picture-in-picture aspect ratio.
*/
void setPictureInPictureAspectRatio(float aspectRatio) {
- if (!mWmService.mSupportsPictureInPicture) {
+ if (!mWmService.mAtmService.mSupportsPictureInPicture) {
return;
}
@@ -1792,7 +1792,7 @@
* Sets the current picture-in-picture actions.
*/
void setPictureInPictureActions(List<RemoteAction> actions) {
- if (!mWmService.mSupportsPictureInPicture) {
+ if (!mWmService.mAtmService.mSupportsPictureInPicture) {
return;
}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index bbef261..29d232f 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -767,11 +767,11 @@
*/
void setOrientation(int orientation, @Nullable IBinder freezeDisplayToken,
@Nullable ConfigurationContainer requestingContainer) {
- final boolean changed = mOrientation != orientation;
- mOrientation = orientation;
- if (!changed) {
+ if (mOrientation == orientation) {
return;
}
+
+ mOrientation = orientation;
final WindowContainer parent = getParent();
if (parent != null) {
onDescendantOrientationChanged(freezeDisplayToken, requestingContainer);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 86faad0..d8d6841 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -28,6 +28,7 @@
import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
import static android.app.StatusBarManager.DISABLE_MASK;
import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED;
+import static android.content.pm.PackageManager.FEATURE_PC;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Process.SYSTEM_UID;
import static android.os.Process.myPid;
@@ -591,9 +592,6 @@
int mDockedStackCreateMode = SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
Rect mDockedStackCreateBounds;
- boolean mForceResizableTasks;
- boolean mSupportsPictureInPicture;
- boolean mSupportsFreeformWindowManagement;
boolean mIsPc;
/**
* Flag that indicates that desktop mode is forced for public secondary screens.
@@ -819,7 +817,7 @@
int mTransactionSequence;
final WindowAnimator mAnimator;
- final SurfaceAnimationRunner mSurfaceAnimationRunner;
+ SurfaceAnimationRunner mSurfaceAnimationRunner;
/**
* Keeps track of which animations got transferred to which animators. Entries will get cleaned
@@ -957,6 +955,9 @@
final ArrayList<AppFreezeListener> mAppFreezeListeners = new ArrayList<>();
+ @VisibleForTesting
+ final DeviceConfig.OnPropertiesChangedListener mPropertiesChangedListener;
+
interface AppFreezeListener {
void onAppFreezeTimeout();
}
@@ -1010,6 +1011,7 @@
mGlobalLock = atm.getGlobalLock();
mAtmService = atm;
mContext = context;
+ mIsPc = mContext.getPackageManager().hasSystemFeature(FEATURE_PC);
mAllowBootMessages = showBootMsgs;
mOnlyCore = onlyCore;
mLimitedAlphaCompositing = context.getResources().getBoolean(
@@ -1159,26 +1161,28 @@
mSystemGestureExcludedByPreQStickyImmersive =
DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE, false);
- DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
- new HandlerExecutor(mH), properties -> {
- synchronized (mGlobalLock) {
- final int exclusionLimitDp = Math.max(MIN_GESTURE_EXCLUSION_LIMIT_DP,
- properties.getInt(KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP, 0));
- final boolean excludedByPreQSticky = DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_WINDOW_MANAGER,
- KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE, false);
- if (mSystemGestureExcludedByPreQStickyImmersive != excludedByPreQSticky
- || mSystemGestureExclusionLimitDp != exclusionLimitDp) {
- mSystemGestureExclusionLimitDp = exclusionLimitDp;
- mSystemGestureExcludedByPreQStickyImmersive = excludedByPreQSticky;
- mRoot.forAllDisplays(DisplayContent::updateSystemGestureExclusionLimit);
- }
- mSystemGestureExclusionLogDebounceTimeoutMillis =
- DeviceConfig.getInt(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
- KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS, 0);
- }
- });
+ mPropertiesChangedListener = properties -> {
+ synchronized (mGlobalLock) {
+ final int exclusionLimitDp = Math.max(MIN_GESTURE_EXCLUSION_LIMIT_DP,
+ properties.getInt(KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP, 0));
+ final boolean excludedByPreQSticky = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_WINDOW_MANAGER,
+ KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE, false);
+ if (mSystemGestureExcludedByPreQStickyImmersive != excludedByPreQSticky
+ || mSystemGestureExclusionLimitDp != exclusionLimitDp) {
+ mSystemGestureExclusionLimitDp = exclusionLimitDp;
+ mSystemGestureExcludedByPreQStickyImmersive = excludedByPreQSticky;
+ mRoot.forAllDisplays(DisplayContent::updateSystemGestureExclusionLimit);
+ }
+
+ mSystemGestureExclusionLogDebounceTimeoutMillis =
+ DeviceConfig.getInt(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
+ KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS, 0);
+ }
+ };
+ DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
+ new HandlerExecutor(mH), mPropertiesChangedListener);
LocalServices.addService(WindowManagerInternal.class, new LocalService());
}
@@ -2595,7 +2599,7 @@
mRecentsAnimationController = controller;
}
- public RecentsAnimationController getRecentsAnimationController() {
+ RecentsAnimationController getRecentsAnimationController() {
return mRecentsAnimationController;
}
@@ -2603,74 +2607,37 @@
* @return Whether the next recents animation can continue to start. Called from
* {@link RecentsAnimation#startRecentsActivity}.
*/
- public boolean canStartRecentsAnimation() {
- synchronized (mGlobalLock) {
- // TODO(multi-display): currently only default display support recent activity
- if (getDefaultDisplayContentLocked().mAppTransition.isTransitionSet()) {
- return false;
- }
- return true;
+ boolean canStartRecentsAnimation() {
+ // TODO(multi-display): currently only default display support recent activity
+ if (getDefaultDisplayContentLocked().mAppTransition.isTransitionSet()) {
+ return false;
}
+ return true;
}
- /**
- * Cancels any running recents animation. The caller should NOT hold the WM lock while calling
- * this method, as it will call back into AM and may cause a deadlock. Any locking will be done
- * in the animation controller itself.
- */
- public void cancelRecentsAnimationSynchronously(
+ void cancelRecentsAnimation(
@RecentsAnimationController.ReorderMode int reorderMode, String reason) {
if (mRecentsAnimationController != null) {
// This call will call through to cleanupAnimation() below after the animation is
// canceled
- mRecentsAnimationController.cancelAnimationSynchronously(reorderMode, reason);
+ mRecentsAnimationController.cancelAnimation(reorderMode, reason);
}
}
- public void cleanupRecentsAnimation(@RecentsAnimationController.ReorderMode int reorderMode) {
- synchronized (mGlobalLock) {
- if (mRecentsAnimationController != null) {
- final RecentsAnimationController controller = mRecentsAnimationController;
- mRecentsAnimationController = null;
- controller.cleanupAnimation(reorderMode);
- // TODO(mult-display): currently only default display support recents animation.
- getDefaultDisplayContentLocked().mAppTransition.updateBooster();
- }
+ void cleanupRecentsAnimation(@RecentsAnimationController.ReorderMode int reorderMode) {
+ if (mRecentsAnimationController != null) {
+ final RecentsAnimationController controller = mRecentsAnimationController;
+ mRecentsAnimationController = null;
+ controller.cleanupAnimation(reorderMode);
+ // TODO(mult-display): currently only default display support recents animation.
+ getDefaultDisplayContentLocked().mAppTransition.updateBooster();
}
}
- public void setAppFullscreen(IBinder token, boolean toOpaque) {
- synchronized (mGlobalLock) {
- final AppWindowToken atoken = mRoot.getAppWindowToken(token);
- if (atoken != null) {
- atoken.setFillsParent(toOpaque);
- setWindowOpaqueLocked(token, toOpaque);
- mWindowPlacerLocked.requestTraversal();
- }
- }
- }
-
- public void setWindowOpaque(IBinder token, boolean isOpaque) {
- synchronized (mGlobalLock) {
- setWindowOpaqueLocked(token, isOpaque);
- }
- }
-
- private void setWindowOpaqueLocked(IBinder token, boolean isOpaque) {
+ void setWindowOpaqueLocked(IBinder token, boolean isOpaque) {
final AppWindowToken wtoken = mRoot.getAppWindowToken(token);
if (wtoken != null) {
- final WindowState win = wtoken.findMainWindow();
- if (win == null) {
- return;
- }
- isOpaque = isOpaque & !PixelFormat.formatHasAlpha(win.getAttrs().format);
- win.mWinAnimator.setOpaqueLocked(isOpaque);
- }
- }
-
- public void setDockedStackCreateState(int mode, Rect bounds) {
- synchronized (mGlobalLock) {
- setDockedStackCreateStateLocked(mode, bounds);
+ wtoken.setMainWindowOpaque(isOpaque);
}
}
@@ -2679,14 +2646,12 @@
mDockedStackCreateBounds = bounds;
}
- public void checkSplitScreenMinimizedChanged(boolean animate) {
- synchronized (mGlobalLock) {
- final DisplayContent displayContent = getDefaultDisplayContentLocked();
- displayContent.getDockedDividerController().checkMinimizeChanged(animate);
- }
+ void checkSplitScreenMinimizedChanged(boolean animate) {
+ final DisplayContent displayContent = getDefaultDisplayContentLocked();
+ displayContent.getDockedDividerController().checkMinimizeChanged(animate);
}
- public boolean isValidPictureInPictureAspectRatio(int displayId, float aspectRatio) {
+ boolean isValidPictureInPictureAspectRatio(int displayId, float aspectRatio) {
final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
return displayContent.getPinnedStackController().isValidPictureInPictureAspectRatio(
aspectRatio);
@@ -4847,8 +4812,10 @@
case UPDATE_DOCKED_STACK_DIVIDER: {
synchronized (mGlobalLock) {
final DisplayContent displayContent = getDefaultDisplayContentLocked();
- displayContent.getDockedDividerController().reevaluateVisibility(false);
- displayContent.adjustForImeIfNeeded();
+ if (displayContent != null) {
+ displayContent.getDockedDividerController().reevaluateVisibility(false);
+ displayContent.adjustForImeIfNeeded();
+ }
}
break;
}
@@ -6495,31 +6462,14 @@
}
}
- public void setForceResizableTasks(boolean forceResizableTasks) {
- synchronized (mGlobalLock) {
- mForceResizableTasks = forceResizableTasks;
- }
- }
-
- public void setSupportsPictureInPicture(boolean supportsPictureInPicture) {
- synchronized (mGlobalLock) {
- mSupportsPictureInPicture = supportsPictureInPicture;
- }
- }
-
- public void setSupportsFreeformWindowManagement(boolean supportsFreeformWindowManagement) {
- synchronized (mGlobalLock) {
- mSupportsFreeformWindowManagement = supportsFreeformWindowManagement;
- }
- }
-
void setForceDesktopModeOnExternalDisplays(boolean forceDesktopModeOnExternalDisplays) {
synchronized (mGlobalLock) {
mForceDesktopModeOnExternalDisplays = forceDesktopModeOnExternalDisplays;
}
}
- public void setIsPc(boolean isPc) {
+ @VisibleForTesting
+ void setIsPc(boolean isPc) {
synchronized (mGlobalLock) {
mIsPc = isPc;
}
@@ -6546,7 +6496,7 @@
"registerPinnedStackListener()")) {
return;
}
- if (!mSupportsPictureInPicture) {
+ if (!mAtmService.mSupportsPictureInPicture) {
return;
}
synchronized (mGlobalLock) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index e14514b..d87a0ed 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -5125,9 +5125,17 @@
// relative layering of multiple APPLICATION_MEDIA/OVERLAY has never
// been defined and so we can use static layers and leave it that way.
if (w.mAttrs.type == TYPE_APPLICATION_MEDIA) {
- w.assignLayer(t, -2);
+ if (mWinAnimator.hasSurface()) {
+ w.assignRelativeLayer(t, mWinAnimator.mSurfaceController.mSurfaceControl, -2);
+ } else {
+ w.assignLayer(t, -2);
+ }
} else if (w.mAttrs.type == TYPE_APPLICATION_MEDIA_OVERLAY) {
- w.assignLayer(t, -1);
+ if (mWinAnimator.hasSurface()) {
+ w.assignRelativeLayer(t, mWinAnimator.mSurfaceController.mSurfaceControl, -1);
+ } else {
+ w.assignLayer(t, -1);
+ }
} else {
w.assignLayer(t, layer);
}
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 466ca93..03f4755 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -165,6 +165,7 @@
outPointerIcon->bitmap.readPixels(bitmapCopy->info(), bitmapCopy->getPixels(),
bitmapCopy->rowBytes(), 0, 0);
}
+ outSpriteIcon->style = outPointerIcon->style;
outSpriteIcon->hotSpotX = outPointerIcon->hotSpotX;
outSpriteIcon->hotSpotY = outPointerIcon->hotSpotY;
}
@@ -1252,7 +1253,8 @@
status_t status = android_view_PointerIcon_load(env, pointerIconObj.get(),
displayContext.get(), &pointerIcon);
if (!status && !pointerIcon.isNullIcon()) {
- *icon = SpriteIcon(pointerIcon.bitmap, pointerIcon.hotSpotX, pointerIcon.hotSpotY);
+ *icon = SpriteIcon(
+ pointerIcon.bitmap, pointerIcon.style, pointerIcon.hotSpotX, pointerIcon.hotSpotY);
} else {
*icon = SpriteIcon();
}
@@ -1293,10 +1295,12 @@
milliseconds_to_nanoseconds(pointerIcon.durationPerFrame);
animationData.animationFrames.reserve(numFrames);
animationData.animationFrames.push_back(SpriteIcon(
- pointerIcon.bitmap, pointerIcon.hotSpotX, pointerIcon.hotSpotY));
+ pointerIcon.bitmap, pointerIcon.style,
+ pointerIcon.hotSpotX, pointerIcon.hotSpotY));
for (size_t i = 0; i < numFrames - 1; ++i) {
animationData.animationFrames.push_back(SpriteIcon(
- pointerIcon.bitmapFrames[i], pointerIcon.hotSpotX, pointerIcon.hotSpotY));
+ pointerIcon.bitmapFrames[i], pointerIcon.style,
+ pointerIcon.hotSpotX, pointerIcon.hotSpotY));
}
}
}
@@ -1711,6 +1715,7 @@
pointerIcon.bitmap.readPixels(spriteInfo, spriteIcon.bitmap.getPixels(),
spriteIcon.bitmap.rowBytes(), 0, 0);
}
+ spriteIcon.style = pointerIcon.style;
spriteIcon.hotSpotX = pointerIcon.hotSpotX;
spriteIcon.hotSpotY = pointerIcon.hotSpotY;
im->setCustomPointerIcon(spriteIcon);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 3d2a3f6..67ae407 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -40,7 +40,9 @@
import android.database.sqlite.SQLiteCompatibilityWalFlags;
import android.database.sqlite.SQLiteGlobal;
import android.hardware.display.DisplayManagerInternal;
+import android.net.ConnectivityModuleConnector;
import android.net.NetworkStackClient;
+import android.net.wifi.WifiStackClient;
import android.os.BaseBundle;
import android.os.Binder;
import android.os.Build;
@@ -633,6 +635,13 @@
SystemServerInitThreadPool.get().submit(SystemConfig::getInstance, TAG_SYSTEM_CONFIG);
t.traceEnd();
+ // Platform compat service is used by ActivityManagerService, PackageManagerService, and
+ // possibly others in the future. b/135010838.
+ t.traceBegin("PlatformCompat");
+ ServiceManager.addService(Context.PLATFORM_COMPAT_SERVICE,
+ new PlatformCompat(mSystemContext));
+ t.traceEnd();
+
// Wait for installd to finish starting up so that it has a chance to
// create critical directories such as /data/user with the appropriate
// permissions. We need this to complete before we initialize other services.
@@ -1100,10 +1109,6 @@
SignedConfigService.registerUpdateReceiver(mSystemContext);
t.traceEnd();
- t.traceBegin("PlatformCompat");
- ServiceManager.addService("platform_compat", new PlatformCompat(context));
- t.traceEnd();
-
} catch (RuntimeException e) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting core service", e);
@@ -1283,6 +1288,14 @@
Slog.d(TAG, "ContentSuggestionsService not defined by OEM");
}
+ t.traceBegin("InitConnectivityModuleConnector");
+ try {
+ ConnectivityModuleConnector.getInstance().init(context);
+ } catch (Throwable e) {
+ reportWtf("initializing ConnectivityModuleConnector", e);
+ }
+ t.traceEnd();
+
t.traceBegin("InitNetworkStackClient");
try {
NetworkStackClient.getInstance().init();
@@ -1345,40 +1358,6 @@
t.traceEnd();
if (context.getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_WIFI)) {
- // Wifi Service must be started first for wifi-related services.
- t.traceBegin("StartWifi");
- mSystemServiceManager.startService(WIFI_SERVICE_CLASS);
- t.traceEnd();
- t.traceBegin("StartWifiScanning");
- mSystemServiceManager.startService(
- "com.android.server.wifi.scanner.WifiScanningService");
- t.traceEnd();
- }
-
- if (context.getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_WIFI_RTT)) {
- t.traceBegin("StartRttService");
- mSystemServiceManager.startService(
- "com.android.server.wifi.rtt.RttService");
- t.traceEnd();
- }
-
- if (context.getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_WIFI_AWARE)) {
- t.traceBegin("StartWifiAware");
- mSystemServiceManager.startService(WIFI_AWARE_SERVICE_CLASS);
- t.traceEnd();
- }
-
- if (context.getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_WIFI_DIRECT)) {
- t.traceBegin("StartWifiP2P");
- mSystemServiceManager.startService(WIFI_P2P_SERVICE_CLASS);
- t.traceEnd();
- }
-
- if (context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_LOWPAN)) {
t.traceBegin("StartLowpan");
mSystemServiceManager.startService(LOWPAN_SERVICE_CLASS);
@@ -2177,12 +2156,21 @@
// ActivityManagerService.mSystemReady and ActivityManagerService.mProcessesReady
// are set to true. Be careful if moving this to a different place in the
// startup sequence.
- NetworkStackClient.getInstance().start(context);
+ NetworkStackClient.getInstance().start();
} catch (Throwable e) {
reportWtf("starting Network Stack", e);
}
t.traceEnd();
+ t.traceBegin("StartWifiStack");
+ try {
+ WifiStackClient.getInstance().start();
+ } catch (Throwable e) {
+ reportWtf("starting Wifi Stack", e);
+ }
+ t.traceEnd();
+
+
t.traceBegin("MakeLocationServiceReady");
try {
if (locationF != null) {
diff --git a/services/net/java/android/net/ConnectivityModuleConnector.java b/services/net/java/android/net/ConnectivityModuleConnector.java
new file mode 100644
index 0000000..7333f58
--- /dev/null
+++ b/services/net/java/android/net/ConnectivityModuleConnector.java
@@ -0,0 +1,389 @@
+/*
+ * 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.net;
+
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
+import android.net.util.SharedLog;
+import android.os.Build;
+import android.os.Environment;
+import android.os.IBinder;
+import android.os.Process;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.provider.DeviceConfig;
+import android.text.format.DateUtils;
+import android.util.ArraySet;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.io.File;
+import java.io.PrintWriter;
+
+/**
+ * Class used to communicate to the various networking mainline modules running in the network stack
+ * process from {@link com.android.server.SystemServer}.
+ * @hide
+ */
+public class ConnectivityModuleConnector {
+ private static final String TAG = ConnectivityModuleConnector.class.getSimpleName();
+ private static final String IN_PROCESS_SUFFIX = ".InProcess";
+
+ private static final String PREFS_FILE = "ConnectivityModuleConnector.xml";
+ private static final String PREF_KEY_LAST_CRASH_TIME = "lastcrash_time";
+ private static final String CONFIG_MIN_CRASH_INTERVAL_MS = "min_crash_interval";
+ private static final String CONFIG_MIN_UPTIME_BEFORE_CRASH_MS = "min_uptime_before_crash";
+ private static final String CONFIG_ALWAYS_RATELIMIT_NETWORKSTACK_CRASH =
+ "always_ratelimit_networkstack_crash";
+
+ // Even if the network stack is lost, do not crash the system more often than this.
+ // Connectivity would be broken, but if the user needs the device for something urgent
+ // (like calling emergency services) we should not bootloop the device.
+ // This is the default value: the actual value can be adjusted via device config.
+ private static final long DEFAULT_MIN_CRASH_INTERVAL_MS = 6 * DateUtils.HOUR_IN_MILLIS;
+
+ // Even if the network stack is lost, do not crash the system server if it was less than
+ // this much after boot. This avoids bootlooping the device, and crashes should address very
+ // infrequent failures, not failures on boot.
+ private static final long DEFAULT_MIN_UPTIME_BEFORE_CRASH_MS = 30 * DateUtils.MINUTE_IN_MILLIS;
+
+ private static ConnectivityModuleConnector sInstance;
+
+ private Context mContext;
+ @GuardedBy("mLog")
+ private final SharedLog mLog = new SharedLog(TAG);
+ @GuardedBy("mHealthListeners")
+ private final ArraySet<ConnectivityModuleHealthListener> mHealthListeners = new ArraySet<>();
+
+ private ConnectivityModuleConnector() { }
+
+ /**
+ * Get the {@link ConnectivityModuleConnector} singleton instance.
+ */
+ public static synchronized ConnectivityModuleConnector getInstance() {
+ if (sInstance == null) {
+ sInstance = new ConnectivityModuleConnector();
+ }
+ return sInstance;
+ }
+
+ /**
+ * Initialize the network stack connector. Should be called only once on device startup, before
+ * any client attempts to use the network stack.
+ */
+ public void init(Context context) {
+ log("Network stack init");
+ mContext = context;
+ }
+
+ /**
+ * Callback interface for severe failures of the NetworkStack.
+ *
+ * <p>Useful for health monitors such as PackageWatchdog.
+ */
+ public interface ConnectivityModuleHealthListener {
+ /**
+ * Called when there is a severe failure of the network stack.
+ * @param packageName Package name of the network stack.
+ */
+ void onNetworkStackFailure(@NonNull String packageName);
+ }
+
+ /**
+ * Callback invoked by the connector once the connection to the corresponding module is
+ * established.
+ */
+ public interface ModuleServiceCallback {
+ /**
+ * Invoked when the corresponding service has connected.
+ *
+ * @param iBinder Binder object for the service.
+ */
+ void onModuleServiceConnected(@NonNull IBinder iBinder);
+ }
+
+
+ /**
+ * Add a {@link ConnectivityModuleHealthListener} to listen to network stack health events.
+ */
+ public void registerHealthListener(@NonNull ConnectivityModuleHealthListener listener) {
+ synchronized (mHealthListeners) {
+ mHealthListeners.add(listener);
+ }
+ }
+
+ /**
+ * Start a module running in the network stack or system_server process. Should be called only
+ * once for each module per device startup.
+ *
+ * <p>This method will start a networking module either in the network stack
+ * process, or inside the system server on devices that do not support the corresponding
+ * mainline network . The corresponding networking module service's binder
+ * object will then be delivered asynchronously via the provided {@link ModuleServiceCallback}.
+ *
+ * @param serviceIntentBaseAction Base action to use for constructing the intent needed to
+ * bind to the corresponding module.
+ * @param servicePermissionName Permission to be held by the corresponding module.
+ */
+ public void startModuleService(
+ @NonNull String serviceIntentBaseAction,
+ @NonNull String servicePermissionName,
+ @NonNull ModuleServiceCallback callback) {
+ log("Starting networking module " + serviceIntentBaseAction);
+
+ final PackageManager pm = mContext.getPackageManager();
+
+ // Try to bind in-process if the device was shipped with an in-process version
+ Intent intent = getModuleServiceIntent(pm, serviceIntentBaseAction, servicePermissionName,
+ true /* inSystemProcess */);
+
+ // Otherwise use the updatable module version
+ if (intent == null) {
+ intent = getModuleServiceIntent(pm, serviceIntentBaseAction, servicePermissionName,
+ false /* inSystemProcess */);
+ log("Starting networking module in network_stack process");
+ } else {
+ log("Starting networking module in system_server process");
+ }
+
+ if (intent == null) {
+ maybeCrashWithTerribleFailure("Could not resolve the networking module", null);
+ return;
+ }
+
+ final String packageName = intent.getComponent().getPackageName();
+
+ // Start the network stack. The service will be added to the service manager by the
+ // corresponding client in ModuleServiceCallback.onModuleServiceConnected().
+ if (!mContext.bindServiceAsUser(
+ intent, new ModuleServiceConnection(packageName, callback),
+ Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.SYSTEM)) {
+ maybeCrashWithTerribleFailure(
+ "Could not bind to networking module in-process, or in app with "
+ + intent, packageName);
+ return;
+ }
+
+ log("Networking module service start requested");
+ }
+
+ private class ModuleServiceConnection implements ServiceConnection {
+ @NonNull
+ private final String mPackageName;
+ @NonNull
+ private final ModuleServiceCallback mModuleServiceCallback;
+
+ private ModuleServiceConnection(
+ @NonNull String packageName,
+ @NonNull ModuleServiceCallback moduleCallback) {
+ mPackageName = packageName;
+ mModuleServiceCallback = moduleCallback;
+ }
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ logi("Networking module service connected");
+ mModuleServiceCallback.onModuleServiceConnected(service);
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ // onServiceDisconnected is not being called on device shutdown, so this method being
+ // called always indicates a bad state for the system server.
+ // This code path is only run by the system server: only the system server binds
+ // to the NetworkStack as a service. Other processes get the NetworkStack from
+ // the ServiceManager.
+ maybeCrashWithTerribleFailure("Lost network stack", mPackageName);
+ }
+ }
+
+ @Nullable
+ private Intent getModuleServiceIntent(
+ @NonNull PackageManager pm, @NonNull String serviceIntentBaseAction,
+ @NonNull String servicePermissionName, boolean inSystemProcess) {
+ final Intent intent =
+ new Intent(inSystemProcess
+ ? serviceIntentBaseAction + IN_PROCESS_SUFFIX
+ : serviceIntentBaseAction);
+ final ComponentName comp = intent.resolveSystemService(pm, 0);
+ if (comp == null) {
+ return null;
+ }
+ intent.setComponent(comp);
+
+ int uid = -1;
+ try {
+ uid = pm.getPackageUidAsUser(comp.getPackageName(), UserHandle.USER_SYSTEM);
+ } catch (PackageManager.NameNotFoundException e) {
+ logWtf("Networking module package not found", e);
+ // Fall through
+ }
+
+ final int expectedUid = inSystemProcess ? Process.SYSTEM_UID : Process.NETWORK_STACK_UID;
+ if (uid != expectedUid) {
+ throw new SecurityException("Invalid network stack UID: " + uid);
+ }
+
+ if (!inSystemProcess) {
+ checkModuleServicePermission(pm, comp, servicePermissionName);
+ }
+
+ return intent;
+ }
+
+ private void checkModuleServicePermission(
+ @NonNull PackageManager pm, @NonNull ComponentName comp,
+ @NonNull String servicePermissionName) {
+ final int hasPermission =
+ pm.checkPermission(servicePermissionName, comp.getPackageName());
+ if (hasPermission != PERMISSION_GRANTED) {
+ throw new SecurityException(
+ "Networking module does not have permission " + servicePermissionName);
+ }
+ }
+
+ private synchronized void maybeCrashWithTerribleFailure(@NonNull String message,
+ @Nullable String packageName) {
+ logWtf(message, null);
+ // uptime is monotonic even after a framework restart
+ final long uptime = SystemClock.elapsedRealtime();
+ final long now = System.currentTimeMillis();
+ final long minCrashIntervalMs = DeviceConfig.getLong(DeviceConfig.NAMESPACE_CONNECTIVITY,
+ CONFIG_MIN_CRASH_INTERVAL_MS, DEFAULT_MIN_CRASH_INTERVAL_MS);
+ final long minUptimeBeforeCrash = DeviceConfig.getLong(DeviceConfig.NAMESPACE_CONNECTIVITY,
+ CONFIG_MIN_UPTIME_BEFORE_CRASH_MS, DEFAULT_MIN_UPTIME_BEFORE_CRASH_MS);
+ final boolean alwaysRatelimit = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_CONNECTIVITY,
+ CONFIG_ALWAYS_RATELIMIT_NETWORKSTACK_CRASH, false);
+
+ final SharedPreferences prefs = getSharedPreferences();
+ final long lastCrashTime = tryGetLastCrashTime(prefs);
+
+ // Only crash if there was enough time since boot, and (if known) enough time passed since
+ // the last crash.
+ // time and lastCrashTime may be unreliable if devices have incorrect clock time, but they
+ // are only used to limit the number of crashes compared to only using the time since boot,
+ // which would also be OK behavior by itself.
+ // - If lastCrashTime is incorrectly more than the current time, only look at uptime
+ // - If it is much less than current time, only look at uptime
+ // - If current time is during the next few hours after last crash time, don't crash.
+ // Considering that this only matters if last boot was some time ago, it's likely that
+ // time will be set correctly. Otherwise, not crashing is not a big problem anyway. Being
+ // in this last state would also not last for long since the window is only a few hours.
+ final boolean alwaysCrash = Build.IS_DEBUGGABLE && !alwaysRatelimit;
+ final boolean justBooted = uptime < minUptimeBeforeCrash;
+ final boolean haveLastCrashTime = (lastCrashTime != 0) && (lastCrashTime < now);
+ final boolean haveKnownRecentCrash =
+ haveLastCrashTime && (now < lastCrashTime + minCrashIntervalMs);
+ if (alwaysCrash || (!justBooted && !haveKnownRecentCrash)) {
+ // The system is not bound to its network stack (for example due to a crash in the
+ // network stack process): better crash rather than stay in a bad state where all
+ // networking is broken.
+ // Using device-encrypted SharedPreferences as DeviceConfig does not have a synchronous
+ // API to persist settings before a crash.
+ tryWriteLastCrashTime(prefs, now);
+ throw new IllegalStateException(message);
+ }
+
+ // Here the system crashed recently already. Inform listeners that something is
+ // definitely wrong.
+ if (packageName != null) {
+ final ArraySet<ConnectivityModuleHealthListener> listeners;
+ synchronized (mHealthListeners) {
+ listeners = new ArraySet<>(mHealthListeners);
+ }
+ for (ConnectivityModuleHealthListener listener : listeners) {
+ listener.onNetworkStackFailure(packageName);
+ }
+ }
+ }
+
+ @Nullable
+ private SharedPreferences getSharedPreferences() {
+ try {
+ final File prefsFile = new File(
+ Environment.getDataSystemDeDirectory(UserHandle.USER_SYSTEM), PREFS_FILE);
+ return mContext.createDeviceProtectedStorageContext()
+ .getSharedPreferences(prefsFile, Context.MODE_PRIVATE);
+ } catch (Throwable e) {
+ logWtf("Error loading shared preferences", e);
+ return null;
+ }
+ }
+
+ private long tryGetLastCrashTime(@Nullable SharedPreferences prefs) {
+ if (prefs == null) return 0L;
+ try {
+ return prefs.getLong(PREF_KEY_LAST_CRASH_TIME, 0L);
+ } catch (Throwable e) {
+ logWtf("Error getting last crash time", e);
+ return 0L;
+ }
+ }
+
+ private void tryWriteLastCrashTime(@Nullable SharedPreferences prefs, long value) {
+ if (prefs == null) return;
+ try {
+ prefs.edit().putLong(PREF_KEY_LAST_CRASH_TIME, value).commit();
+ } catch (Throwable e) {
+ logWtf("Error writing last crash time", e);
+ }
+ }
+
+ private void log(@NonNull String message) {
+ Slog.d(TAG, message);
+ synchronized (mLog) {
+ mLog.log(message);
+ }
+ }
+
+ private void logWtf(@NonNull String message, @Nullable Throwable e) {
+ Slog.wtf(TAG, message, e);
+ synchronized (mLog) {
+ mLog.e(message);
+ }
+ }
+
+ private void loge(@NonNull String message, @Nullable Throwable e) {
+ Slog.e(TAG, message, e);
+ synchronized (mLog) {
+ mLog.e(message);
+ }
+ }
+
+ private void logi(@NonNull String message) {
+ Slog.i(TAG, message);
+ synchronized (mLog) {
+ mLog.i(message);
+ }
+ }
+
+ /**
+ * Dump ConnectivityModuleConnector logs to the specified {@link PrintWriter}.
+ */
+ public void dump(PrintWriter pw) {
+ // dump is thread-safe on SharedLog
+ mLog.dump(null, pw, null);
+ }
+}
diff --git a/services/net/java/android/net/NetworkStackClient.java b/services/net/java/android/net/NetworkStackClient.java
index 56b728c..abb4666 100644
--- a/services/net/java/android/net/NetworkStackClient.java
+++ b/services/net/java/android/net/NetworkStackClient.java
@@ -15,40 +15,27 @@
*/
package android.net;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.content.ComponentName;
import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.content.SharedPreferences;
-import android.content.pm.PackageManager;
import android.net.dhcp.DhcpServingParamsParcel;
import android.net.dhcp.IDhcpServerCallbacks;
import android.net.ip.IIpClientCallbacks;
import android.net.util.SharedLog;
import android.os.Binder;
-import android.os.Build;
-import android.os.Environment;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.SystemClock;
import android.os.UserHandle;
-import android.provider.DeviceConfig;
-import android.text.format.DateUtils;
-import android.util.ArraySet;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
-import java.io.File;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -60,24 +47,6 @@
private static final String TAG = NetworkStackClient.class.getSimpleName();
private static final int NETWORKSTACK_TIMEOUT_MS = 10_000;
- private static final String IN_PROCESS_SUFFIX = ".InProcess";
- private static final String PREFS_FILE = "NetworkStackClientPrefs.xml";
- private static final String PREF_KEY_LAST_CRASH_TIME = "lastcrash_time";
- private static final String CONFIG_MIN_CRASH_INTERVAL_MS = "min_crash_interval";
- private static final String CONFIG_MIN_UPTIME_BEFORE_CRASH_MS = "min_uptime_before_crash";
- private static final String CONFIG_ALWAYS_RATELIMIT_NETWORKSTACK_CRASH =
- "always_ratelimit_networkstack_crash";
-
- // Even if the network stack is lost, do not crash the system more often than this.
- // Connectivity would be broken, but if the user needs the device for something urgent
- // (like calling emergency services) we should not bootloop the device.
- // This is the default value: the actual value can be adjusted via device config.
- private static final long DEFAULT_MIN_CRASH_INTERVAL_MS = 6 * DateUtils.HOUR_IN_MILLIS;
-
- // Even if the network stack is lost, do not crash the system server if it was less than
- // this much after boot. This avoids bootlooping the device, and crashes should address very
- // infrequent failures, not failures on boot.
- private static final long DEFAULT_MIN_UPTIME_BEFORE_CRASH_MS = 30 * DateUtils.MINUTE_IN_MILLIS;
private static NetworkStackClient sInstance;
@@ -93,26 +62,10 @@
private volatile boolean mWasSystemServerInitialized = false;
- @GuardedBy("mHealthListeners")
- private final ArraySet<NetworkStackHealthListener> mHealthListeners = new ArraySet<>();
-
private interface NetworkStackCallback {
void onNetworkStackConnected(INetworkStackConnector connector);
}
- /**
- * Callback interface for severe failures of the NetworkStack.
- *
- * <p>Useful for health monitors such as PackageWatchdog.
- */
- public interface NetworkStackHealthListener {
- /**
- * Called when there is a severe failure of the network stack.
- * @param packageName Package name of the network stack.
- */
- void onNetworkStackFailure(@NonNull String packageName);
- }
-
private NetworkStackClient() { }
/**
@@ -126,15 +79,6 @@
}
/**
- * Add a {@link NetworkStackHealthListener} to listen to network stack health events.
- */
- public void registerHealthListener(@NonNull NetworkStackHealthListener listener) {
- synchronized (mHealthListeners) {
- mHealthListeners.add(listener);
- }
- }
-
- /**
* Create a DHCP server according to the specified parameters.
*
* <p>The server will be returned asynchronously through the provided callbacks.
@@ -195,32 +139,13 @@
});
}
- private class NetworkStackConnection implements ServiceConnection {
- @NonNull
- private final Context mContext;
- @NonNull
- private final String mPackageName;
-
- private NetworkStackConnection(@NonNull Context context, @NonNull String packageName) {
- mContext = context;
- mPackageName = packageName;
- }
-
+ private class NetworkStackConnection implements
+ ConnectivityModuleConnector.ModuleServiceCallback {
@Override
- public void onServiceConnected(ComponentName name, IBinder service) {
+ public void onModuleServiceConnected(IBinder service) {
logi("Network stack service connected");
registerNetworkStackService(service);
}
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- // onServiceDisconnected is not being called on device shutdown, so this method being
- // called always indicates a bad state for the system server.
- // This code path is only run by the system server: only the system server binds
- // to the NetworkStack as a service. Other processes get the NetworkStack from
- // the ServiceManager.
- maybeCrashWithTerribleFailure("Lost network stack", mContext, mPackageName);
- }
}
private void registerNetworkStackService(@NonNull IBinder service) {
@@ -259,171 +184,13 @@
* connector will then be delivered asynchronously to clients that requested it before it was
* started.
*/
- public void start(Context context) {
- log("Starting network stack");
-
- final PackageManager pm = context.getPackageManager();
-
- // Try to bind in-process if the device was shipped with an in-process version
- Intent intent = getNetworkStackIntent(pm, true /* inSystemProcess */);
-
- // Otherwise use the updatable module version
- if (intent == null) {
- intent = getNetworkStackIntent(pm, false /* inSystemProcess */);
- log("Starting network stack process");
- } else {
- log("Starting network stack in-process");
- }
-
- if (intent == null) {
- maybeCrashWithTerribleFailure("Could not resolve the network stack", context, null);
- return;
- }
-
- final String packageName = intent.getComponent().getPackageName();
-
- // Start the network stack. The service will be added to the service manager in
- // NetworkStackConnection.onServiceConnected().
- if (!context.bindServiceAsUser(intent, new NetworkStackConnection(context, packageName),
- Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.SYSTEM)) {
- maybeCrashWithTerribleFailure(
- "Could not bind to network stack in-process, or in app with " + intent,
- context, packageName);
- return;
- }
-
+ public void start() {
+ ConnectivityModuleConnector.getInstance().startModuleService(
+ INetworkStackConnector.class.getName(), PERMISSION_MAINLINE_NETWORK_STACK,
+ new NetworkStackConnection());
log("Network stack service start requested");
}
- @Nullable
- private Intent getNetworkStackIntent(@NonNull PackageManager pm, boolean inSystemProcess) {
- final String baseAction = INetworkStackConnector.class.getName();
- final Intent intent =
- new Intent(inSystemProcess ? baseAction + IN_PROCESS_SUFFIX : baseAction);
- final ComponentName comp = intent.resolveSystemService(pm, 0);
-
- if (comp == null) {
- return null;
- }
- intent.setComponent(comp);
-
- int uid = -1;
- try {
- uid = pm.getPackageUidAsUser(comp.getPackageName(), UserHandle.USER_SYSTEM);
- } catch (PackageManager.NameNotFoundException e) {
- logWtf("Network stack package not found", e);
- // Fall through
- }
-
- final int expectedUid = inSystemProcess ? Process.SYSTEM_UID : Process.NETWORK_STACK_UID;
- if (uid != expectedUid) {
- throw new SecurityException("Invalid network stack UID: " + uid);
- }
-
- if (!inSystemProcess) {
- checkNetworkStackPermission(pm, comp);
- }
-
- return intent;
- }
-
- private void checkNetworkStackPermission(
- @NonNull PackageManager pm, @NonNull ComponentName comp) {
- final int hasPermission =
- pm.checkPermission(PERMISSION_MAINLINE_NETWORK_STACK, comp.getPackageName());
- if (hasPermission != PERMISSION_GRANTED) {
- throw new SecurityException(
- "Network stack does not have permission " + PERMISSION_MAINLINE_NETWORK_STACK);
- }
- }
-
- private void maybeCrashWithTerribleFailure(@NonNull String message,
- @NonNull Context context, @Nullable String packageName) {
- logWtf(message, null);
- // uptime is monotonic even after a framework restart
- final long uptime = SystemClock.elapsedRealtime();
- final long now = System.currentTimeMillis();
- final long minCrashIntervalMs = DeviceConfig.getLong(DeviceConfig.NAMESPACE_CONNECTIVITY,
- CONFIG_MIN_CRASH_INTERVAL_MS, DEFAULT_MIN_CRASH_INTERVAL_MS);
- final long minUptimeBeforeCrash = DeviceConfig.getLong(DeviceConfig.NAMESPACE_CONNECTIVITY,
- CONFIG_MIN_UPTIME_BEFORE_CRASH_MS, DEFAULT_MIN_UPTIME_BEFORE_CRASH_MS);
- final boolean alwaysRatelimit = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_CONNECTIVITY,
- CONFIG_ALWAYS_RATELIMIT_NETWORKSTACK_CRASH, false);
-
- final SharedPreferences prefs = getSharedPreferences(context);
- final long lastCrashTime = tryGetLastCrashTime(prefs);
-
- // Only crash if there was enough time since boot, and (if known) enough time passed since
- // the last crash.
- // time and lastCrashTime may be unreliable if devices have incorrect clock time, but they
- // are only used to limit the number of crashes compared to only using the time since boot,
- // which would also be OK behavior by itself.
- // - If lastCrashTime is incorrectly more than the current time, only look at uptime
- // - If it is much less than current time, only look at uptime
- // - If current time is during the next few hours after last crash time, don't crash.
- // Considering that this only matters if last boot was some time ago, it's likely that
- // time will be set correctly. Otherwise, not crashing is not a big problem anyway. Being
- // in this last state would also not last for long since the window is only a few hours.
- final boolean alwaysCrash = Build.IS_DEBUGGABLE && !alwaysRatelimit;
- final boolean justBooted = uptime < minUptimeBeforeCrash;
- final boolean haveLastCrashTime = (lastCrashTime != 0) && (lastCrashTime < now);
- final boolean haveKnownRecentCrash =
- haveLastCrashTime && (now < lastCrashTime + minCrashIntervalMs);
- if (alwaysCrash || (!justBooted && !haveKnownRecentCrash)) {
- // The system is not bound to its network stack (for example due to a crash in the
- // network stack process): better crash rather than stay in a bad state where all
- // networking is broken.
- // Using device-encrypted SharedPreferences as DeviceConfig does not have a synchronous
- // API to persist settings before a crash.
- tryWriteLastCrashTime(prefs, now);
- throw new IllegalStateException(message);
- }
-
- // Here the system crashed recently already. Inform listeners that something is
- // definitely wrong.
- if (packageName != null) {
- final ArraySet<NetworkStackHealthListener> listeners;
- synchronized (mHealthListeners) {
- listeners = new ArraySet<>(mHealthListeners);
- }
- for (NetworkStackHealthListener listener : listeners) {
- listener.onNetworkStackFailure(packageName);
- }
- }
- }
-
- @Nullable
- private SharedPreferences getSharedPreferences(@NonNull Context context) {
- try {
- final File prefsFile = new File(
- Environment.getDataSystemDeDirectory(UserHandle.USER_SYSTEM), PREFS_FILE);
- return context.createDeviceProtectedStorageContext()
- .getSharedPreferences(prefsFile, Context.MODE_PRIVATE);
- } catch (Throwable e) {
- logWtf("Error loading shared preferences", e);
- return null;
- }
- }
-
- private long tryGetLastCrashTime(@Nullable SharedPreferences prefs) {
- if (prefs == null) return 0L;
- try {
- return prefs.getLong(PREF_KEY_LAST_CRASH_TIME, 0L);
- } catch (Throwable e) {
- logWtf("Error getting last crash time", e);
- return 0L;
- }
- }
-
- private void tryWriteLastCrashTime(@Nullable SharedPreferences prefs, long value) {
- if (prefs == null) return;
- try {
- prefs.edit().putLong(PREF_KEY_LAST_CRASH_TIME, value).commit();
- } catch (Throwable e) {
- logWtf("Error writing last crash time", e);
- }
- }
-
/**
* Log a message in the local log.
*/
@@ -524,6 +291,8 @@
public void dump(PrintWriter pw) {
// dump is thread-safe on SharedLog
mLog.dump(null, pw, null);
+ // dump connectivity module connector logs.
+ ConnectivityModuleConnector.getInstance().dump(pw);
final int requestsQueueLength;
synchronized (mPendingNetStackRequests) {
diff --git a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java
similarity index 78%
rename from services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java
rename to services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java
index 0d99561..a1bfcdf 100644
--- a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -36,8 +36,6 @@
import static org.robolectric.Shadows.shadowOf;
import static org.testng.Assert.expectThrows;
-import static java.util.Collections.emptySet;
-
import android.annotation.UserIdInt;
import android.app.Application;
import android.app.backup.IBackupManagerMonitor;
@@ -48,16 +46,19 @@
import android.content.Intent;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
+import android.os.Process;
import android.os.UserHandle;
+import android.os.UserManager;
import android.platform.test.annotations.Presubmit;
import android.util.SparseArray;
import com.android.server.backup.testing.TransportData;
import com.android.server.testing.shadows.ShadowApplicationPackageManager;
import com.android.server.testing.shadows.ShadowBinder;
+import com.android.server.testing.shadows.ShadowEnvironment;
import com.android.server.testing.shadows.ShadowSystemServiceRegistry;
+import com.android.server.testing.shadows.ShadowUserManager;
-import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -66,6 +67,7 @@
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
+import org.robolectric.shadow.api.Shadow;
import org.robolectric.shadows.ShadowContextWrapper;
import java.io.File;
@@ -74,28 +76,32 @@
import java.io.PrintWriter;
import java.io.StringWriter;
-/** Tests for the user-aware backup/restore system service {@link BackupManagerService}. */
+/** Tests for {@link BackupManagerService}. */
@RunWith(RobolectricTestRunner.class)
@Config(
shadows = {
- ShadowApplicationPackageManager.class,
- ShadowBinder.class,
- ShadowSystemServiceRegistry.class
+ ShadowApplicationPackageManager.class,
+ ShadowBinder.class,
+ ShadowUserManager.class,
+ ShadowEnvironment.class,
+ ShadowSystemServiceRegistry.class
})
@Presubmit
-public class BackupManagerServiceTest {
+public class BackupManagerServiceRoboTest {
private static final String TEST_PACKAGE = "package";
private static final String TEST_TRANSPORT = "transport";
private static final String[] ADB_TEST_PACKAGES = {TEST_PACKAGE};
- private ShadowContextWrapper mShadowContext;
private Context mContext;
+ private ShadowContextWrapper mShadowContext;
+ private ShadowUserManager mShadowUserManager;
@UserIdInt private int mUserOneId;
@UserIdInt private int mUserTwoId;
+ @Mock private UserBackupManagerService mUserSystemService;
@Mock private UserBackupManagerService mUserOneService;
@Mock private UserBackupManagerService mUserTwoService;
- /** Initialize {@link BackupManagerService}. */
+ /** Setup */
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
@@ -103,66 +109,26 @@
Application application = RuntimeEnvironment.application;
mContext = application;
mShadowContext = shadowOf(application);
+ mShadowUserManager = Shadow.extract(UserManager.get(application));
mUserOneId = UserHandle.USER_SYSTEM + 1;
mUserTwoId = mUserOneId + 1;
- }
+ mShadowUserManager.addUser(mUserOneId, "mUserOneId", 0);
+ mShadowUserManager.addUser(mUserTwoId, "mUserTwoId", 0);
- /**
- * Clean up and reset state that was created for testing {@link BackupManagerService}
- * operations.
- */
- @After
- public void tearDown() throws Exception {
- ShadowBinder.reset();
- }
+ mShadowContext.grantPermissions(BACKUP);
+ mShadowContext.grantPermissions(INTERACT_ACROSS_USERS_FULL);
- /**
- * Test verifying that {@link BackupManagerService#MORE_DEBUG} is set to {@code false}. This is
- * specifically to prevent overloading the logs in production.
- */
- @Test
- public void testMoreDebug_isFalse() throws Exception {
- boolean moreDebug = BackupManagerService.MORE_DEBUG;
-
- assertThat(moreDebug).isFalse();
- }
-
- /** Test that the constructor does not create {@link UserBackupManagerService} instances. */
- @Test
- public void testConstructor_doesNotRegisterUsers() throws Exception {
- BackupManagerService backupManagerService = createService();
-
- assertThat(backupManagerService.getUserServices().size()).isEqualTo(0);
- }
-
- /** Test that the constructor handles {@code null} parameters. */
- @Test
- public void testConstructor_withNullContext_throws() throws Exception {
- expectThrows(
- NullPointerException.class,
- () ->
- new BackupManagerService(
- /* context */ null,
- new Trampoline(mContext)));
- }
-
- /** Test that the constructor handles {@code null} parameters. */
- @Test
- public void testConstructor_withNullTrampoline_throws() throws Exception {
- expectThrows(
- NullPointerException.class,
- () ->
- new BackupManagerService(
- mContext, /* trampoline */ null));
+ ShadowBinder.setCallingUid(Process.SYSTEM_UID);
}
/** Test that the service registers users. */
@Test
public void testStartServiceForUser_registersUser() throws Exception {
BackupManagerService backupManagerService = createService();
+ backupManagerService.setBackupServiceActive(mUserOneId, true);
- backupManagerService.startServiceForUser(mUserOneId, emptySet());
+ backupManagerService.startServiceForUser(mUserOneId);
SparseArray<UserBackupManagerService> serviceUsers = backupManagerService.getUserServices();
assertThat(serviceUsers.size()).isEqualTo(1);
@@ -173,6 +139,7 @@
@Test
public void testStartServiceForUser_withServiceInstance_registersUser() throws Exception {
BackupManagerService backupManagerService = createService();
+ backupManagerService.setBackupServiceActive(mUserOneId, true);
backupManagerService.startServiceForUser(mUserOneId, mUserOneService);
@@ -187,6 +154,7 @@
BackupManagerService backupManagerService =
createServiceAndRegisterUser(mUserOneId, mUserOneService);
backupManagerService.startServiceForUser(mUserTwoId, mUserTwoService);
+ ShadowBinder.setCallingUid(Process.SYSTEM_UID);
backupManagerService.stopServiceForUser(mUserOneId);
@@ -201,6 +169,7 @@
public void testStopServiceForUser_forRegisteredUser_tearsDownCorrectUser() throws Exception {
BackupManagerService backupManagerService =
createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ backupManagerService.setBackupServiceActive(mUserTwoId, true);
backupManagerService.startServiceForUser(mUserTwoId, mUserTwoService);
backupManagerService.stopServiceForUser(mUserOneId);
@@ -213,6 +182,8 @@
@Test
public void testStopServiceForUser_forUnknownUser_doesNothing() throws Exception {
BackupManagerService backupManagerService = createService();
+ backupManagerService.setBackupServiceActive(mUserOneId, true);
+ ShadowBinder.setCallingUid(Process.SYSTEM_UID);
backupManagerService.stopServiceForUser(mUserOneId);
@@ -220,53 +191,6 @@
assertThat(serviceUsers.size()).isEqualTo(0);
}
- /**
- * Test that the backup services throws a {@link SecurityException} if the caller does not have
- * INTERACT_ACROSS_USERS_FULL permission and passes a different user id.
- */
- @Test
- public void testGetServiceForUser_withoutPermission_throwsSecurityExceptionForNonCallingUser() {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
- setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
-
- expectThrows(
- SecurityException.class,
- () ->
- backupManagerService.getServiceForUserIfCallerHasPermission(
- mUserOneId, "test"));
- }
-
- /**
- * Test that the backup services does not throw a {@link SecurityException} if the caller has
- * INTERACT_ACROSS_USERS_FULL permission and passes a different user id.
- */
- @Test
- public void testGetServiceForUserIfCallerHasPermission_withPermission_worksForNonCallingUser() {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
- setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ true);
-
- assertEquals(
- mUserOneService,
- backupManagerService.getServiceForUserIfCallerHasPermission(mUserOneId, "test"));
- }
-
- /**
- * Test that the backup services does not throw a {@link SecurityException} if the caller does
- * not have INTERACT_ACROSS_USERS_FULL permission and passes in the calling user id.
- */
- @Test
- public void testGetServiceForUserIfCallerHasPermission_withoutPermission_worksForCallingUser() {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
- setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
-
- assertEquals(
- mUserOneService,
- backupManagerService.getServiceForUserIfCallerHasPermission(mUserOneId, "test"));
- }
-
// ---------------------------------------------
// Backup agent tests
// ---------------------------------------------
@@ -274,8 +198,8 @@
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testDataChanged_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
backupManagerService.dataChanged(mUserOneId, TEST_PACKAGE);
@@ -286,8 +210,8 @@
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testDataChanged_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
backupManagerService.dataChanged(mUserTwoId, TEST_PACKAGE);
@@ -298,8 +222,8 @@
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testAgentConnected_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
IBinder agentBinder = mock(IBinder.class);
@@ -311,8 +235,8 @@
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testAgentConnected_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
IBinder agentBinder = mock(IBinder.class);
@@ -323,33 +247,9 @@
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
- public void testAgentDisconnected_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
- setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
-
- backupManagerService.agentDisconnected(mUserOneId, TEST_PACKAGE);
-
- verify(mUserOneService).agentDisconnected(TEST_PACKAGE);
- }
-
- /** Test that the backup service does not route methods for non-registered users. */
- @Test
- public void testAgentDisconnected_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
- setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
-
- backupManagerService.agentDisconnected(mUserTwoId, TEST_PACKAGE);
-
- verify(mUserOneService, never()).agentDisconnected(TEST_PACKAGE);
- }
-
- /** Test that the backup service routes methods correctly to the user that requests it. */
- @Test
public void testOpComplete_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
backupManagerService.opComplete(mUserOneId, /* token */ 0, /* result */ 0L);
@@ -360,8 +260,8 @@
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testOpComplete_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
backupManagerService.opComplete(mUserTwoId, /* token */ 0, /* result */ 0L);
@@ -376,8 +276,8 @@
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testInitializeTransports_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
String[] transports = {TEST_TRANSPORT};
@@ -389,8 +289,8 @@
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testInitializeTransports_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
String[] transports = {TEST_TRANSPORT};
@@ -402,8 +302,8 @@
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testClearBackupData_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
backupManagerService.clearBackupData(mUserOneId, TEST_TRANSPORT, TEST_PACKAGE);
@@ -414,8 +314,8 @@
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testClearBackupData_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
backupManagerService.clearBackupData(mUserTwoId, TEST_TRANSPORT, TEST_PACKAGE);
@@ -426,8 +326,8 @@
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testGetCurrentTransport_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
backupManagerService.getCurrentTransport(mUserOneId);
@@ -438,8 +338,8 @@
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testGetCurrentTransport_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
backupManagerService.getCurrentTransport(mUserTwoId);
@@ -451,8 +351,8 @@
@Test
public void testGetCurrentTransportComponent_onRegisteredUser_callsMethodForUser()
throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
backupManagerService.getCurrentTransportComponent(mUserOneId);
@@ -464,8 +364,8 @@
@Test
public void testGetCurrentTransportComponent_onUnknownUser_doesNotPropagateCall()
throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
backupManagerService.getCurrentTransportComponent(mUserTwoId);
@@ -476,8 +376,8 @@
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testListAllTransports_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
backupManagerService.listAllTransports(mUserOneId);
@@ -488,8 +388,8 @@
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testListAllTransports_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
backupManagerService.listAllTransports(mUserTwoId);
@@ -501,8 +401,8 @@
@Test
public void testListAllTransportComponents_onRegisteredUser_callsMethodForUser()
throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
backupManagerService.listAllTransportComponents(mUserOneId);
@@ -514,8 +414,8 @@
@Test
public void testListAllTransportComponents_onUnknownUser_doesNotPropagateCall()
throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
backupManagerService.listAllTransportComponents(mUserTwoId);
@@ -525,10 +425,163 @@
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
+ public void testSelectBackupTransport_onRegisteredUser_callsMethodForUser() throws Exception {
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
+ setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
+
+ backupManagerService.selectBackupTransport(mUserOneId, TEST_TRANSPORT);
+
+ verify(mUserOneService).selectBackupTransport(TEST_TRANSPORT);
+ }
+
+ /** Test that the backup service does not route methods for non-registered users. */
+ @Test
+ public void testSelectBackupTransport_onUnknownUser_doesNotPropagateCall() throws Exception {
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
+ setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
+
+ backupManagerService.selectBackupTransport(mUserTwoId, TEST_TRANSPORT);
+
+ verify(mUserOneService, never()).selectBackupTransport(TEST_TRANSPORT);
+ }
+
+ /** Test that the backup service routes methods correctly to the user that requests it. */
+ @Test
+ public void testSelectTransportAsync_onRegisteredUser_callsMethodForUser() throws Exception {
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
+ setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
+ TransportData transport = backupTransport();
+ ISelectBackupTransportCallback callback = mock(ISelectBackupTransportCallback.class);
+
+ backupManagerService.selectBackupTransportAsync(
+ mUserOneId, transport.getTransportComponent(), callback);
+
+ verify(mUserOneService)
+ .selectBackupTransportAsync(transport.getTransportComponent(), callback);
+ }
+
+ /** Test that the backup service does not route methods for non-registered users. */
+ @Test
+ public void testSelectBackupTransportAsync_onUnknownUser_doesNotPropagateCall()
+ throws Exception {
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
+ setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
+ TransportData transport = backupTransport();
+ ISelectBackupTransportCallback callback = mock(ISelectBackupTransportCallback.class);
+
+ backupManagerService.selectBackupTransportAsync(
+ mUserTwoId, transport.getTransportComponent(), callback);
+
+ verify(mUserOneService, never())
+ .selectBackupTransportAsync(transport.getTransportComponent(), callback);
+ }
+
+ /** Test that the backup service routes methods correctly to the user that requests it. */
+ @Test
+ public void testGetConfigurationIntent_onRegisteredUser_callsMethodForUser() throws Exception {
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
+ setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
+
+ backupManagerService.getConfigurationIntent(mUserOneId, TEST_TRANSPORT);
+
+ verify(mUserOneService).getConfigurationIntent(TEST_TRANSPORT);
+ }
+
+ /** Test that the backup service does not route methods for non-registered users. */
+ @Test
+ public void testGetConfigurationIntent_onUnknownUser_doesNotPropagateCall() throws Exception {
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
+ setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
+
+ backupManagerService.getConfigurationIntent(mUserTwoId, TEST_TRANSPORT);
+
+ verify(mUserOneService, never()).getConfigurationIntent(TEST_TRANSPORT);
+ }
+
+ /** Test that the backup service routes methods correctly to the user that requests it. */
+ @Test
+ public void testGetDestinationString_onRegisteredUser_callsMethodForUser() throws Exception {
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
+ setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
+
+ backupManagerService.getDestinationString(mUserOneId, TEST_TRANSPORT);
+
+ verify(mUserOneService).getDestinationString(TEST_TRANSPORT);
+ }
+
+ /** Test that the backup service does not route methods for non-registered users. */
+ @Test
+ public void testGetDestinationString_onUnknownUser_doesNotPropagateCall() throws Exception {
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
+ setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
+
+ backupManagerService.getDestinationString(mUserTwoId, TEST_TRANSPORT);
+
+ verify(mUserOneService, never()).getDestinationString(TEST_TRANSPORT);
+ }
+
+ /** Test that the backup service routes methods correctly to the user that requests it. */
+ @Test
+ public void testGetDataManagementIntent_onRegisteredUser_callsMethodForUser() throws Exception {
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
+ setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
+
+ backupManagerService.getDataManagementIntent(mUserOneId, TEST_TRANSPORT);
+
+ verify(mUserOneService).getDataManagementIntent(TEST_TRANSPORT);
+ }
+
+ /** Test that the backup service does not route methods for non-registered users. */
+ @Test
+ public void testGetDataManagementIntent_onUnknownUser_doesNotPropagateCall() throws Exception {
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
+ setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
+
+ backupManagerService.getDataManagementIntent(mUserTwoId, TEST_TRANSPORT);
+
+ verify(mUserOneService, never()).getDataManagementIntent(TEST_TRANSPORT);
+ }
+
+ /** Test that the backup service routes methods correctly to the user that requests it. */
+ @Test
+ public void testGetDataManagementLabel_onRegisteredUser_callsMethodForUser() throws Exception {
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
+ setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
+
+ backupManagerService.getDataManagementLabel(mUserOneId, TEST_TRANSPORT);
+
+ verify(mUserOneService).getDataManagementLabel(TEST_TRANSPORT);
+ }
+
+ /** Test that the backup service does not route methods for non-registered users. */
+ @Test
+ public void testGetDataManagementLabel_onUnknownUser_doesNotPropagateCall() throws Exception {
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
+ setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
+
+ backupManagerService.getDataManagementLabel(mUserTwoId, TEST_TRANSPORT);
+
+ verify(mUserOneService, never()).getDataManagementLabel(TEST_TRANSPORT);
+ }
+
+ /** Test that the backup service routes methods correctly to the user that requests it. */
+ @Test
public void testUpdateTransportAttributes_onRegisteredUser_callsMethodForUser()
throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
TransportData transport = backupTransport();
Intent configurationIntent = new Intent();
@@ -557,8 +610,8 @@
@Test
public void testUpdateTransportAttributes_onUnknownUser_doesNotPropagateCall()
throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
TransportData transport = backupTransport();
Intent configurationIntent = new Intent();
@@ -583,170 +636,18 @@
"dataManagementLabel");
}
- /** Test that the backup service routes methods correctly to the user that requests it. */
- @Test
- public void testSelectBackupTransport_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
- setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
-
- backupManagerService.selectBackupTransport(mUserOneId, TEST_TRANSPORT);
-
- verify(mUserOneService).selectBackupTransport(TEST_TRANSPORT);
- }
-
- /** Test that the backup service does not route methods for non-registered users. */
- @Test
- public void testSelectBackupTransport_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
- setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
-
- backupManagerService.selectBackupTransport(mUserTwoId, TEST_TRANSPORT);
-
- verify(mUserOneService, never()).selectBackupTransport(TEST_TRANSPORT);
- }
-
- /** Test that the backup service routes methods correctly to the user that requests it. */
- @Test
- public void testSelectTransportAsync_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
- setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
- TransportData transport = backupTransport();
- ISelectBackupTransportCallback callback = mock(ISelectBackupTransportCallback.class);
-
- backupManagerService.selectBackupTransportAsync(
- mUserOneId, transport.getTransportComponent(), callback);
-
- verify(mUserOneService)
- .selectBackupTransportAsync(transport.getTransportComponent(), callback);
- }
-
- /** Test that the backup service does not route methods for non-registered users. */
- @Test
- public void testSelectBackupTransportAsync_onUnknownUser_doesNotPropagateCall()
- throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
- setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
- TransportData transport = backupTransport();
- ISelectBackupTransportCallback callback = mock(ISelectBackupTransportCallback.class);
-
- backupManagerService.selectBackupTransportAsync(
- mUserTwoId, transport.getTransportComponent(), callback);
-
- verify(mUserOneService, never())
- .selectBackupTransportAsync(transport.getTransportComponent(), callback);
- }
-
- /** Test that the backup service routes methods correctly to the user that requests it. */
- @Test
- public void testGetConfigurationIntent_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
- setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
-
- backupManagerService.getConfigurationIntent(mUserOneId, TEST_TRANSPORT);
-
- verify(mUserOneService).getConfigurationIntent(TEST_TRANSPORT);
- }
-
- /** Test that the backup service does not route methods for non-registered users. */
- @Test
- public void testGetConfigurationIntent_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
- setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
-
- backupManagerService.getConfigurationIntent(mUserTwoId, TEST_TRANSPORT);
-
- verify(mUserOneService, never()).getConfigurationIntent(TEST_TRANSPORT);
- }
-
- /** Test that the backup service routes methods correctly to the user that requests it. */
- @Test
- public void testGetDestinationString_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
- setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
-
- backupManagerService.getDestinationString(mUserOneId, TEST_TRANSPORT);
-
- verify(mUserOneService).getDestinationString(TEST_TRANSPORT);
- }
-
- /** Test that the backup service does not route methods for non-registered users. */
- @Test
- public void testGetDestinationString_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
- setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
-
- backupManagerService.getDestinationString(mUserTwoId, TEST_TRANSPORT);
-
- verify(mUserOneService, never()).getDestinationString(TEST_TRANSPORT);
- }
-
- /** Test that the backup service routes methods correctly to the user that requests it. */
- @Test
- public void testGetDataManagementIntent_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
- setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
-
- backupManagerService.getDataManagementIntent(mUserOneId, TEST_TRANSPORT);
-
- verify(mUserOneService).getDataManagementIntent(TEST_TRANSPORT);
- }
-
- /** Test that the backup service does not route methods for non-registered users. */
- @Test
- public void testGetDataManagementIntent_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
- setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
-
- backupManagerService.getDataManagementIntent(mUserTwoId, TEST_TRANSPORT);
-
- verify(mUserOneService, never()).getDataManagementIntent(TEST_TRANSPORT);
- }
-
- /** Test that the backup service routes methods correctly to the user that requests it. */
- @Test
- public void testGetDataManagementLabel_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
- setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
-
- backupManagerService.getDataManagementLabel(mUserOneId, TEST_TRANSPORT);
-
- verify(mUserOneService).getDataManagementLabel(TEST_TRANSPORT);
- }
-
- /** Test that the backup service does not route methods for non-registered users. */
- @Test
- public void testGetDataManagementLabel_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
- setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
-
- backupManagerService.getDataManagementLabel(mUserTwoId, TEST_TRANSPORT);
-
- verify(mUserOneService, never()).getDataManagementLabel(TEST_TRANSPORT);
- }
-
// ---------------------------------------------
// Settings tests
// ---------------------------------------------
+
/**
* Test that the backup services throws a {@link SecurityException} if the caller does not have
* INTERACT_ACROSS_USERS_FULL permission and passes a different user id.
*/
@Test
public void testSetBackupEnabled_withoutPermission_throwsSecurityExceptionForNonCallingUser() {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
expectThrows(
@@ -760,9 +661,10 @@
*/
@Test
public void testSetBackupEnabled_withPermission_propagatesForNonCallingUser() {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
- backupManagerService.startServiceForUser(mUserTwoId, mUserTwoService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
+ registerUser(backupManagerService, mUserTwoId, mUserTwoService);
+
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ true);
backupManagerService.setBackupEnabled(mUserTwoId, true);
@@ -773,8 +675,8 @@
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testSetBackupEnabled_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
backupManagerService.setBackupEnabled(mUserOneId, true);
@@ -785,8 +687,8 @@
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testSetBackupEnabled_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
backupManagerService.setBackupEnabled(mUserTwoId, true);
@@ -797,8 +699,8 @@
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testSetAutoRestore_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
backupManagerService.setAutoRestore(mUserOneId, true);
@@ -809,8 +711,8 @@
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testSetAutoRestore_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
backupManagerService.setAutoRestore(mUserTwoId, true);
@@ -821,8 +723,8 @@
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testIsBackupEnabled_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
backupManagerService.isBackupEnabled(mUserOneId);
@@ -833,8 +735,8 @@
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testIsBackupEnabled_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
backupManagerService.isBackupEnabled(mUserTwoId);
@@ -849,8 +751,8 @@
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testIsAppEligibleForBackup_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
backupManagerService.isAppEligibleForBackup(mUserOneId, TEST_PACKAGE);
@@ -861,8 +763,8 @@
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testIsAppEligibleForBackup_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
backupManagerService.isAppEligibleForBackup(mUserTwoId, TEST_PACKAGE);
@@ -874,8 +776,8 @@
@Test
public void testFilterAppsEligibleForBackup_onRegisteredUser_callsMethodForUser()
throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
String[] packages = {TEST_PACKAGE};
@@ -888,8 +790,8 @@
@Test
public void testFilterAppsEligibleForBackup_onUnknownUser_doesNotPropagateCall()
throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
String[] packages = {TEST_PACKAGE};
@@ -904,8 +806,8 @@
*/
@Test
public void testBackupNow_withoutPermission_throwsSecurityExceptionForNonCallingUser() {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
expectThrows(SecurityException.class, () -> backupManagerService.backupNow(mUserTwoId));
@@ -917,9 +819,10 @@
*/
@Test
public void testBackupNow_withPermission_propagatesForNonCallingUser() {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
- backupManagerService.startServiceForUser(mUserTwoId, mUserTwoService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
+ registerUser(backupManagerService, mUserTwoId, mUserTwoService);
+
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ true);
backupManagerService.backupNow(mUserTwoId);
@@ -930,8 +833,8 @@
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testBackupNow_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
backupManagerService.backupNow(mUserOneId);
@@ -942,8 +845,8 @@
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testBackupNow_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
backupManagerService.backupNow(mUserTwoId);
@@ -957,8 +860,8 @@
*/
@Test
public void testRequestBackup_withoutPermission_throwsSecurityExceptionForNonCallingUser() {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
String[] packages = {TEST_PACKAGE};
IBackupObserver observer = mock(IBackupObserver.class);
@@ -977,9 +880,10 @@
*/
@Test
public void testRequestBackup_withPermission_propagatesForNonCallingUser() {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
- backupManagerService.startServiceForUser(mUserTwoId, mUserTwoService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
+ registerUser(backupManagerService, mUserTwoId, mUserTwoService);
+
String[] packages = {TEST_PACKAGE};
IBackupObserver observer = mock(IBackupObserver.class);
IBackupManagerMonitor monitor = mock(IBackupManagerMonitor.class);
@@ -993,8 +897,8 @@
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testRequestBackup_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
String[] packages = {TEST_PACKAGE};
IBackupObserver observer = mock(IBackupObserver.class);
IBackupManagerMonitor monitor = mock(IBackupManagerMonitor.class);
@@ -1008,8 +912,8 @@
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testRequestBackup_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
String[] packages = {TEST_PACKAGE};
IBackupObserver observer = mock(IBackupObserver.class);
IBackupManagerMonitor monitor = mock(IBackupManagerMonitor.class);
@@ -1026,8 +930,8 @@
*/
@Test
public void testCancelBackups_withoutPermission_throwsSecurityExceptionForNonCallingUser() {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
expectThrows(SecurityException.class, () -> backupManagerService.cancelBackups(mUserTwoId));
@@ -1039,9 +943,9 @@
*/
@Test
public void testCancelBackups_withPermission_propagatesForNonCallingUser() {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
- backupManagerService.startServiceForUser(mUserTwoId, mUserTwoService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
+ registerUser(backupManagerService, mUserTwoId, mUserTwoService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ true);
backupManagerService.cancelBackups(mUserTwoId);
@@ -1052,8 +956,8 @@
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testCancelBackups_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
backupManagerService.cancelBackups(mUserOneId);
@@ -1064,8 +968,8 @@
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testCancelBackups_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
backupManagerService.cancelBackups(mUserTwoId);
@@ -1076,8 +980,8 @@
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testBeginFullBackup_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(UserHandle.USER_SYSTEM, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, UserHandle.USER_SYSTEM, mUserOneService);
FullBackupJob job = new FullBackupJob();
backupManagerService.beginFullBackup(UserHandle.USER_SYSTEM, job);
@@ -1099,8 +1003,8 @@
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testEndFullBackup_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(UserHandle.USER_SYSTEM, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, UserHandle.USER_SYSTEM, mUserOneService);
backupManagerService.endFullBackup(UserHandle.USER_SYSTEM);
@@ -1120,8 +1024,8 @@
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testFullTransportBackup_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
String[] packages = {TEST_PACKAGE};
@@ -1133,8 +1037,8 @@
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testFullTransportBackup_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
String[] packages = {TEST_PACKAGE};
@@ -1150,8 +1054,8 @@
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testRestoreAtInstall_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
backupManagerService.restoreAtInstall(mUserOneId, TEST_PACKAGE, /* token */ 0);
@@ -1162,8 +1066,8 @@
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testRestoreAtInstall_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
backupManagerService.restoreAtInstall(mUserTwoId, TEST_PACKAGE, /* token */ 0);
@@ -1174,8 +1078,8 @@
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testBeginRestoreSession_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
backupManagerService.beginRestoreSession(mUserOneId, TEST_PACKAGE, TEST_TRANSPORT);
@@ -1186,8 +1090,8 @@
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testBeginRestoreSession_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
backupManagerService.beginRestoreSession(mUserTwoId, TEST_PACKAGE, TEST_TRANSPORT);
@@ -1199,8 +1103,8 @@
@Test
public void testGetAvailableRestoreToken_onRegisteredUser_callsMethodForUser()
throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
backupManagerService.getAvailableRestoreToken(mUserOneId, TEST_PACKAGE);
@@ -1211,8 +1115,8 @@
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testGetAvailableRestoreToken_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
backupManagerService.getAvailableRestoreToken(mUserTwoId, TEST_PACKAGE);
@@ -1227,8 +1131,9 @@
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testSetBackupPassword_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(UserHandle.USER_SYSTEM, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, UserHandle.USER_SYSTEM, mUserOneService);
+ ShadowBinder.setCallingUserHandle(UserHandle.of(UserHandle.USER_SYSTEM));
backupManagerService.setBackupPassword("currentPassword", "newPassword");
@@ -1248,8 +1153,9 @@
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testHasBackupPassword_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(UserHandle.USER_SYSTEM, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, UserHandle.USER_SYSTEM, mUserOneService);
+ ShadowBinder.setCallingUserHandle(UserHandle.of(UserHandle.USER_SYSTEM));
backupManagerService.hasBackupPassword();
@@ -1272,8 +1178,9 @@
*/
@Test
public void testAdbBackup_withoutPermission_throwsSecurityExceptionForNonCallingUser() {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createSystemRegisteredService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
+ registerUser(backupManagerService, mUserTwoId, mUserTwoService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
expectThrows(
@@ -1299,9 +1206,10 @@
*/
@Test
public void testAdbBackup_withPermission_propagatesForNonCallingUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
- backupManagerService.startServiceForUser(mUserTwoId, mUserTwoService);
+ BackupManagerService backupManagerService = createSystemRegisteredService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
+ registerUser(backupManagerService, mUserTwoId, mUserTwoService);
+
ParcelFileDescriptor parcelFileDescriptor = getFileDescriptorForAdbTest();
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ true);
@@ -1335,8 +1243,8 @@
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testAdbBackup_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createSystemRegisteredService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
ParcelFileDescriptor parcelFileDescriptor = getFileDescriptorForAdbTest();
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
@@ -1370,8 +1278,8 @@
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testAdbBackup_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createSystemRegisteredService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
ParcelFileDescriptor parcelFileDescriptor = getFileDescriptorForAdbTest();
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
@@ -1408,8 +1316,9 @@
*/
@Test
public void testAdbRestore_withoutPermission_throwsSecurityExceptionForNonCallingUser() {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createSystemRegisteredService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
+ registerUser(backupManagerService, mUserTwoId, mUserTwoService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
expectThrows(
@@ -1422,9 +1331,9 @@
*/
@Test
public void testAdbRestore_withPermission_propagatesForNonCallingUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
- backupManagerService.startServiceForUser(mUserTwoId, mUserTwoService);
+ BackupManagerService backupManagerService = createSystemRegisteredService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
+ registerUser(backupManagerService, mUserTwoId, mUserTwoService);
ParcelFileDescriptor parcelFileDescriptor = getFileDescriptorForAdbTest();
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ true);
@@ -1436,8 +1345,8 @@
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testAdbRestore_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createSystemRegisteredService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
ParcelFileDescriptor parcelFileDescriptor = getFileDescriptorForAdbTest();
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
@@ -1449,8 +1358,8 @@
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testAdbRestore_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createSystemRegisteredService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
ParcelFileDescriptor parcelFileDescriptor = getFileDescriptorForAdbTest();
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
@@ -1459,12 +1368,18 @@
verify(mUserOneService, never()).adbRestore(parcelFileDescriptor);
}
+ private ParcelFileDescriptor getFileDescriptorForAdbTest() throws Exception {
+ File testFile = new File(mContext.getFilesDir(), "test");
+ testFile.createNewFile();
+ return ParcelFileDescriptor.open(testFile, ParcelFileDescriptor.MODE_READ_WRITE);
+ }
+
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testAcknowledgeAdbBackupOrRestore_onRegisteredUser_callsMethodForUser()
throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
IFullBackupRestoreObserver observer = mock(IFullBackupRestoreObserver.class);
@@ -1489,8 +1404,8 @@
@Test
public void testAcknowledgeAdbBackupOrRestore_onUnknownUser_doesNotPropagateCall()
throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
IFullBackupRestoreObserver observer = mock(IFullBackupRestoreObserver.class);
@@ -1512,48 +1427,6 @@
}
// ---------------------------------------------
- // Lifecycle tests
- // ---------------------------------------------
-
-
- /** testOnStart_publishesService */
- @Test
- public void testOnStart_publishesService() {
- Trampoline trampoline = mock(Trampoline.class);
- BackupManagerService.Lifecycle lifecycle =
- spy(new BackupManagerService.Lifecycle(mContext, trampoline));
- doNothing().when(lifecycle).publishService(anyString(), any());
-
- lifecycle.onStart();
-
- verify(lifecycle).publishService(Context.BACKUP_SERVICE, trampoline);
- }
-
- /** testOnUnlockUser_forwards */
- @Test
- public void testOnUnlockUser_forwards() {
- Trampoline trampoline = mock(Trampoline.class);
- BackupManagerService.Lifecycle lifecycle =
- new BackupManagerService.Lifecycle(mContext, trampoline);
-
- lifecycle.onUnlockUser(UserHandle.USER_SYSTEM);
-
- verify(trampoline).onUnlockUser(UserHandle.USER_SYSTEM);
- }
-
- /** testOnStopUser_forwards */
- @Test
- public void testOnStopUser_forwards() {
- Trampoline trampoline = mock(Trampoline.class);
- BackupManagerService.Lifecycle lifecycle =
- new BackupManagerService.Lifecycle(mContext, trampoline);
-
- lifecycle.onStopUser(UserHandle.USER_SYSTEM);
-
- verify(trampoline).onStopUser(UserHandle.USER_SYSTEM);
- }
-
- // ---------------------------------------------
// Service tests
// ---------------------------------------------
@@ -1561,24 +1434,22 @@
@Test
public void testDump_onRegisteredUser_callsMethodForUser() throws Exception {
grantDumpPermissions();
-
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(UserHandle.USER_SYSTEM, mUserOneService);
+ BackupManagerService backupManagerService = createSystemRegisteredService();
File testFile = createTestFile();
FileDescriptor fileDescriptor = new FileDescriptor();
PrintWriter printWriter = new PrintWriter(testFile);
String[] args = {"1", "2"};
+ ShadowBinder.setCallingUserHandle(UserHandle.of(UserHandle.USER_SYSTEM));
backupManagerService.dump(fileDescriptor, printWriter, args);
- verify(mUserOneService).dump(fileDescriptor, printWriter, args);
+ verify(mUserSystemService).dump(fileDescriptor, printWriter, args);
}
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testDump_onUnknownUser_doesNotPropagateCall() throws Exception {
grantDumpPermissions();
-
BackupManagerService backupManagerService = createService();
File testFile = createTestFile();
FileDescriptor fileDescriptor = new FileDescriptor();
@@ -1594,9 +1465,8 @@
@Test
public void testDump_users_dumpsListOfRegisteredUsers() {
grantDumpPermissions();
-
- BackupManagerService backupManagerService = createServiceAndRegisterUser(mUserOneId,
- mUserOneService);
+ BackupManagerService backupManagerService = createSystemRegisteredService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
StringWriter out = new StringWriter();
PrintWriter writer = new PrintWriter(out);
String[] args = {"users"};
@@ -1605,30 +1475,162 @@
writer.flush();
assertEquals(
- String.format("%s %d\n", BackupManagerService.DUMP_RUNNING_USERS_MESSAGE,
- mUserOneId),
+ String.format("%s %d %d\n", BackupManagerService.DUMP_RUNNING_USERS_MESSAGE,
+ UserHandle.USER_SYSTEM, mUserOneId),
out.toString());
}
- private void grantDumpPermissions() {
- mShadowContext.grantPermissions(DUMP);
- mShadowContext.grantPermissions(PACKAGE_USAGE_STATS);
- }
-
private File createTestFile() throws IOException {
File testFile = new File(mContext.getFilesDir(), "test");
testFile.createNewFile();
return testFile;
}
+ private void grantDumpPermissions() {
+ mShadowContext.grantPermissions(DUMP);
+ mShadowContext.grantPermissions(PACKAGE_USAGE_STATS);
+ }
+
+ /**
+ * Test that the backup services throws a {@link SecurityException} if the caller does not have
+ * INTERACT_ACROSS_USERS_FULL permission and passes a different user id.
+ */
+ @Test
+ public void testGetServiceForUser_withoutPermission_throwsSecurityExceptionForNonCallingUser() {
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
+ setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
+
+ expectThrows(
+ SecurityException.class,
+ () ->
+ backupManagerService.getServiceForUserIfCallerHasPermission(
+ mUserOneId, "test"));
+ }
+
+ /**
+ * Test that the backup services does not throw a {@link SecurityException} if the caller has
+ * INTERACT_ACROSS_USERS_FULL permission and passes a different user id.
+ */
+ @Test
+ public void testGetServiceForUserIfCallerHasPermission_withPermission_worksForNonCallingUser() {
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
+ setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ true);
+
+ assertEquals(
+ mUserOneService,
+ backupManagerService.getServiceForUserIfCallerHasPermission(mUserOneId, "test"));
+ }
+
+ /**
+ * Test that the backup services does not throw a {@link SecurityException} if the caller does
+ * not have INTERACT_ACROSS_USERS_FULL permission and passes in the calling user id.
+ */
+ @Test
+ public void testGetServiceForUserIfCallerHasPermission_withoutPermission_worksForCallingUser() {
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
+ setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
+
+ assertEquals(
+ mUserOneService,
+ backupManagerService.getServiceForUserIfCallerHasPermission(mUserOneId, "test"));
+ }
+
+ /**
+ * Test verifying that {@link BackupManagerService#MORE_DEBUG} is set to {@code false}. This is
+ * specifically to prevent overloading the logs in production.
+ */
+ @Test
+ public void testMoreDebug_isFalse() throws Exception {
+ boolean moreDebug = BackupManagerService.MORE_DEBUG;
+
+ assertThat(moreDebug).isFalse();
+ }
+
+ /** Test that the constructor handles {@code null} parameters. */
+ @Test
+ public void testConstructor_withNullContext_throws() throws Exception {
+ expectThrows(
+ NullPointerException.class,
+ () ->
+ new BackupManagerService(
+ /* context */ null,
+ new SparseArray<>()));
+ }
+
+ /** Test that the constructor does not create {@link UserBackupManagerService} instances. */
+ @Test
+ public void testConstructor_doesNotRegisterUsers() throws Exception {
+ BackupManagerService backupManagerService = createService();
+
+ assertThat(backupManagerService.getUserServices().size()).isEqualTo(0);
+ }
+
+ // ---------------------------------------------
+ // Lifecycle tests
+ // ---------------------------------------------
+
+ /** testOnStart_publishesService */
+ @Test
+ public void testOnStart_publishesService() {
+ BackupManagerService backupManagerService = mock(BackupManagerService.class);
+ BackupManagerService.Lifecycle lifecycle =
+ spy(new BackupManagerService.Lifecycle(mContext, backupManagerService));
+ doNothing().when(lifecycle).publishService(anyString(), any());
+
+ lifecycle.onStart();
+
+ verify(lifecycle).publishService(Context.BACKUP_SERVICE, backupManagerService);
+ }
+
+ /** testOnUnlockUser_forwards */
+ @Test
+ public void testOnUnlockUser_forwards() {
+ BackupManagerService backupManagerService = mock(BackupManagerService.class);
+ BackupManagerService.Lifecycle lifecycle =
+ new BackupManagerService.Lifecycle(mContext, backupManagerService);
+
+ lifecycle.onUnlockUser(UserHandle.USER_SYSTEM);
+
+ verify(backupManagerService).onUnlockUser(UserHandle.USER_SYSTEM);
+ }
+
+ /** testOnStopUser_forwards */
+ @Test
+ public void testOnStopUser_forwards() {
+ BackupManagerService backupManagerService = mock(BackupManagerService.class);
+ BackupManagerService.Lifecycle lifecycle =
+ new BackupManagerService.Lifecycle(mContext, backupManagerService);
+
+ lifecycle.onStopUser(UserHandle.USER_SYSTEM);
+
+ verify(backupManagerService).onStopUser(UserHandle.USER_SYSTEM);
+ }
+
private BackupManagerService createService() {
- mShadowContext.grantPermissions(BACKUP);
- return new BackupManagerService(mContext, new Trampoline(mContext));
+ return new BackupManagerService(mContext);
+ }
+
+ private BackupManagerService createSystemRegisteredService() {
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, UserHandle.USER_SYSTEM, mUserSystemService);
+ return backupManagerService;
+ }
+
+ private void registerUser(
+ BackupManagerService backupManagerService,
+ int userId,
+ UserBackupManagerService userBackupManagerService) {
+ backupManagerService.setBackupServiceActive(userId, true);
+ backupManagerService.startServiceForUser(userId, userBackupManagerService);
}
private BackupManagerService createServiceAndRegisterUser(
int userId, UserBackupManagerService userBackupManagerService) {
BackupManagerService backupManagerService = createService();
+ backupManagerService.setBackupServiceActive(userBackupManagerService.getUserId(), true);
backupManagerService.startServiceForUser(userId, userBackupManagerService);
return backupManagerService;
}
@@ -1647,10 +1649,4 @@
mShadowContext.denyPermissions(INTERACT_ACROSS_USERS_FULL);
}
}
-
- private ParcelFileDescriptor getFileDescriptorForAdbTest() throws Exception {
- File testFile = new File(mContext.getFilesDir(), "test");
- testFile.createNewFile();
- return ParcelFileDescriptor.open(testFile, ParcelFileDescriptor.MODE_READ_WRITE);
- }
}
diff --git a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
index 84e810d..8632ca4 100644
--- a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
@@ -1005,7 +1005,7 @@
UserBackupManagerService.createAndInitializeService(
USER_ID,
mContext,
- new Trampoline(mContext),
+ new BackupManagerService(mContext),
mBackupThread,
mBaseStateDir,
mDataDir,
@@ -1026,7 +1026,7 @@
UserBackupManagerService.createAndInitializeService(
USER_ID,
mContext,
- new Trampoline(mContext),
+ new BackupManagerService(mContext),
mBackupThread,
mBaseStateDir,
mDataDir,
@@ -1045,7 +1045,7 @@
UserBackupManagerService.createAndInitializeService(
USER_ID,
/* context */ null,
- new Trampoline(mContext),
+ new BackupManagerService(mContext),
mBackupThread,
mBaseStateDir,
mDataDir,
@@ -1077,7 +1077,7 @@
UserBackupManagerService.createAndInitializeService(
USER_ID,
mContext,
- new Trampoline(mContext),
+ new BackupManagerService(mContext),
/* backupThread */ null,
mBaseStateDir,
mDataDir,
@@ -1093,7 +1093,7 @@
UserBackupManagerService.createAndInitializeService(
USER_ID,
mContext,
- new Trampoline(mContext),
+ new BackupManagerService(mContext),
mBackupThread,
/* baseStateDir */ null,
mDataDir,
@@ -1102,8 +1102,8 @@
/**
* Test checking non-null argument on {@link
- * UserBackupManagerService#createAndInitializeService(int, Context, Trampoline, HandlerThread,
- * File, File, TransportManager)}.
+ * UserBackupManagerService#createAndInitializeService(int, Context, BackupManagerService,
+ * HandlerThread, File, File, TransportManager)}.
*/
@Test
public void testCreateAndInitializeService_withNullDataDir_throws() {
@@ -1113,7 +1113,7 @@
UserBackupManagerService.createAndInitializeService(
USER_ID,
mContext,
- new Trampoline(mContext),
+ new BackupManagerService(mContext),
mBackupThread,
mBaseStateDir,
/* dataDir */ null,
@@ -1122,8 +1122,8 @@
/**
* Test checking non-null argument on {@link
- * UserBackupManagerService#createAndInitializeService(int, Context, Trampoline, HandlerThread,
- * File, File, TransportManager)}.
+ * UserBackupManagerService#createAndInitializeService(int, Context, BackupManagerService,
+ * HandlerThread, File, File, TransportManager)}.
*/
@Test
public void testCreateAndInitializeService_withNullTransportManager_throws() {
@@ -1133,7 +1133,7 @@
UserBackupManagerService.createAndInitializeService(
USER_ID,
mContext,
- new Trampoline(mContext),
+ new BackupManagerService(mContext),
mBackupThread,
mBaseStateDir,
mDataDir,
@@ -1151,7 +1151,7 @@
UserBackupManagerService service = UserBackupManagerService.createAndInitializeService(
USER_ID,
contextSpy,
- new Trampoline(mContext),
+ new BackupManagerService(mContext),
mBackupThread,
mBaseStateDir,
mDataDir,
diff --git a/services/robotests/backup/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java b/services/robotests/backup/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java
index 392d182..84421ef 100644
--- a/services/robotests/backup/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java
+++ b/services/robotests/backup/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java
@@ -37,7 +37,7 @@
import android.util.Log;
import com.android.server.backup.BackupAgentTimeoutParameters;
-import com.android.server.backup.Trampoline;
+import com.android.server.backup.BackupManagerService;
import com.android.server.backup.TransportManager;
import com.android.server.backup.UserBackupManagerService;
@@ -89,7 +89,7 @@
UserBackupManagerService.createAndInitializeService(
userId,
context,
- new Trampoline(context),
+ new BackupManagerService(context),
backupThread,
baseStateDir,
dataDir,
diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowEnvironment.java b/services/robotests/src/com/android/server/testing/shadows/ShadowEnvironment.java
new file mode 100644
index 0000000..577b082
--- /dev/null
+++ b/services/robotests/src/com/android/server/testing/shadows/ShadowEnvironment.java
@@ -0,0 +1,50 @@
+/*
+ * 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.testing.shadows;
+
+import android.annotation.Nullable;
+import android.os.Environment;
+
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.annotation.Resetter;
+
+import java.io.File;
+import java.nio.file.Path;
+
+/** Implementation mimics {@link org.robolectric.shadows.ShadowEnvironment}. */
+@Implements(Environment.class)
+public class ShadowEnvironment extends org.robolectric.shadows.ShadowEnvironment {
+ @Nullable private static Path sDataDirectory;
+
+ /** @see Environment#getDataDirectory() */
+ @Implementation
+ public static File getDataDirectory() {
+ if (sDataDirectory == null) {
+ sDataDirectory = RuntimeEnvironment.getTempDirectory().create("data");
+ }
+ return sDataDirectory.toFile();
+ }
+
+ /** Resets static state. */
+ @Resetter
+ public static void reset() {
+ org.robolectric.shadows.ShadowEnvironment.reset();
+ sDataDirectory = null;
+ }
+}
diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowUserManager.java b/services/robotests/src/com/android/server/testing/shadows/ShadowUserManager.java
new file mode 100644
index 0000000..c6ae1a1
--- /dev/null
+++ b/services/robotests/src/com/android/server/testing/shadows/ShadowUserManager.java
@@ -0,0 +1,33 @@
+/*
+ * 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.testing.shadows;
+
+import android.annotation.UserIdInt;
+import android.os.UserManager;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+
+/** Shadow for {@link UserManager}. */
+@Implements(UserManager.class)
+public class ShadowUserManager extends org.robolectric.shadows.ShadowUserManager {
+ /** @see UserManager#isUserUnlocked() */
+ @Implementation
+ public boolean isUserUnlocked(@UserIdInt int userId) {
+ return false;
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
index 1e29ed6..6e8b86a 100644
--- a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
@@ -253,7 +253,7 @@
doReturn(mIActivityManager).when(ActivityManager::getService);
doReturn(mAppStateTracker).when(() -> LocalServices.getService(AppStateTracker.class));
doReturn(null)
- .when(() -> LocalServices.getService(DeviceIdleController.LocalService.class));
+ .when(() -> LocalServices.getService(DeviceIdleInternal.class));
doReturn(mUsageStatsManagerInternal).when(
() -> LocalServices.getService(UsageStatsManagerInternal.class));
when(mUsageStatsManagerInternal.getAppStandbyBucket(eq(TEST_CALLING_PACKAGE),
diff --git a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
index 6feac52..108b017 100644
--- a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
@@ -186,7 +186,7 @@
@Override
ConstraintController getConstraintController(
- Handler handler, DeviceIdleController.LocalService localService) {
+ Handler handler, DeviceIdleInternal localService) {
return constraintController;
}
@@ -291,7 +291,7 @@
// DeviceIdleController adds these to LocalServices in the constructor, so we have to remove
// them after each test, otherwise, subsequent tests will fail.
LocalServices.removeServiceForTest(AppStateTracker.class);
- LocalServices.removeServiceForTest(DeviceIdleController.LocalService.class);
+ LocalServices.removeServiceForTest(DeviceIdleInternal.class);
}
@Test
diff --git a/services/tests/mockingservicestests/src/com/android/server/deviceidle/BluetoothConstraintTest.java b/services/tests/mockingservicestests/src/com/android/server/deviceidle/BluetoothConstraintTest.java
index f74ac1f..a9d1c2d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/deviceidle/BluetoothConstraintTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/deviceidle/BluetoothConstraintTest.java
@@ -39,7 +39,7 @@
import androidx.test.runner.AndroidJUnit4;
-import com.android.server.DeviceIdleController;
+import com.android.server.DeviceIdleInternal;
import org.junit.After;
import org.junit.Before;
@@ -71,7 +71,7 @@
private BluetoothManager mBluetoothManager;
@Mock
- private DeviceIdleController.LocalService mDeviceIdleService;
+ private DeviceIdleInternal mDeviceIdleService;
private BluetoothConstraint mConstraint;
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
index 22cd3d3..71f7d2c 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
@@ -53,7 +53,7 @@
import android.os.SystemClock;
import com.android.server.AppStateTracker;
-import com.android.server.DeviceIdleController;
+import com.android.server.DeviceIdleInternal;
import com.android.server.LocalServices;
import com.android.server.job.controllers.JobStatus;
@@ -114,8 +114,8 @@
when(mContext.getSystemService(NetworkPolicyManager.class))
.thenReturn(mock(NetworkPolicyManager.class));
// Called in DeviceIdleJobsController constructor.
- doReturn(mock(DeviceIdleController.LocalService.class))
- .when(() -> LocalServices.getService(DeviceIdleController.LocalService.class));
+ doReturn(mock(DeviceIdleInternal.class))
+ .when(() -> LocalServices.getService(DeviceIdleInternal.class));
// Used in JobStatus.
doReturn(mock(PackageManagerInternal.class))
.when(() -> LocalServices.getService(PackageManagerInternal.class));
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 7887d5b..93c16fe 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
@@ -77,6 +77,8 @@
private static final boolean FORCE_SEND = true;
private static final boolean SEND_ON_WINDOW_CHANGES = false;
private static final int USER_SYSTEM_ID = UserHandle.USER_SYSTEM;
+ private static final int USER_PROFILE = 11;
+ private static final int USER_PROFILE_PARENT = 1;
// TO-DO [Multi-Display] : change the display count to 2
private static final int DISPLAY_COUNT = 1;
private static final int NUM_GLOBAL_WINDOWS = 4;
@@ -110,6 +112,8 @@
MockitoAnnotations.initMocks(this);
when(mMockA11yUserManager.getCurrentUserIdLocked()).thenReturn(USER_SYSTEM_ID);
when(mMockA11ySecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(
+ USER_PROFILE)).thenReturn(USER_PROFILE_PARENT);
+ when(mMockA11ySecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(
USER_SYSTEM_ID)).thenReturn(USER_SYSTEM_ID);
when(mMockA11ySecurityPolicy.resolveValidReportedPackageLocked(
anyString(), anyInt(), anyInt())).thenReturn(PACKAGE_NAME);
@@ -247,8 +251,8 @@
throws RemoteException {
final AccessibilityWindowInfo oldWindow =
mA11yWindowManager.getWindowListLocked().get(0);
- final IWindow token =
- addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY, true);
+ final IWindow token = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
+ true, USER_SYSTEM_ID);
final WindowInfo windowInfo = WindowInfo.obtain();
windowInfo.type = AccessibilityWindowInfo.TYPE_APPLICATION;
windowInfo.token = token.asBinder();
@@ -605,6 +609,16 @@
verify(mockRemoteConnection).notifyOutsideTouch();
}
+ @Test
+ public void addAccessibilityInteractionConnection_profileUser_findInParentUser()
+ throws RemoteException {
+ final IWindow token = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
+ false, USER_PROFILE);
+ final int windowId = mA11yWindowManager.findWindowIdLocked(
+ USER_PROFILE_PARENT, token.asBinder());
+ assertTrue(windowId >= 0);
+ }
+
private void startTrackingPerDisplay(int displayId) throws RemoteException {
ArrayList<WindowInfo> windowInfosForDisplay = new ArrayList<>();
// Adds RemoteAccessibilityConnection into AccessibilityWindowManager, and copy
@@ -612,12 +626,14 @@
// for the test.
int layer = 0;
for (int i = 0; i < NUM_GLOBAL_WINDOWS; i++) {
- final IWindow token = addAccessibilityInteractionConnection(displayId, true);
+ final IWindow token = addAccessibilityInteractionConnection(displayId,
+ true, USER_SYSTEM_ID);
addWindowInfo(windowInfosForDisplay, token, layer++);
}
for (int i = 0; i < NUM_APP_WINDOWS; i++) {
- final IWindow token = addAccessibilityInteractionConnection(displayId, false);
+ final IWindow token = addAccessibilityInteractionConnection(displayId,
+ false, USER_SYSTEM_ID);
addWindowInfo(windowInfosForDisplay, token, layer++);
}
// Setups default focus.
@@ -647,8 +663,8 @@
return windowsForAccessibilityCallbacksCaptor.getValue();
}
- private IWindow addAccessibilityInteractionConnection(int displayId, boolean bGlobal)
- throws RemoteException {
+ private IWindow addAccessibilityInteractionConnection(int displayId, boolean bGlobal,
+ int userId) throws RemoteException {
final IWindow mockWindowToken = Mockito.mock(IWindow.class);
final IAccessibilityInteractionConnection mockA11yConnection = Mockito.mock(
IAccessibilityInteractionConnection.class);
@@ -656,13 +672,13 @@
final IBinder mockWindowBinder = Mockito.mock(IBinder.class);
when(mockA11yConnection.asBinder()).thenReturn(mockConnectionBinder);
when(mockWindowToken.asBinder()).thenReturn(mockWindowBinder);
- when(mMockA11ySecurityPolicy.isCallerInteractingAcrossUsers(USER_SYSTEM_ID))
+ when(mMockA11ySecurityPolicy.isCallerInteractingAcrossUsers(userId))
.thenReturn(bGlobal);
when(mMockWindowManagerInternal.getDisplayIdForWindow(mockWindowToken.asBinder()))
.thenReturn(displayId);
int windowId = mA11yWindowManager.addAccessibilityInteractionConnection(
- mockWindowToken, mockA11yConnection, PACKAGE_NAME, USER_SYSTEM_ID);
+ mockWindowToken, mockA11yConnection, PACKAGE_NAME, userId);
mA11yWindowTokens.put(windowId, mockWindowToken);
return mockWindowToken;
}
diff --git a/services/tests/servicestests/src/com/android/server/backup/BackupManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/backup/BackupManagerServiceTest.java
new file mode 100644
index 0000000..68b413f
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/backup/BackupManagerServiceTest.java
@@ -0,0 +1,621 @@
+/*
+ * 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.server.backup;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.fail;
+
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.Manifest;
+import android.annotation.UserIdInt;
+import android.app.backup.BackupManager;
+import android.app.backup.IBackupManagerMonitor;
+import android.app.backup.IBackupObserver;
+import android.app.backup.IFullBackupRestoreObserver;
+import android.app.backup.ISelectBackupTransportCallback;
+import android.app.job.JobScheduler;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.os.ConditionVariable;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.platform.test.annotations.Presubmit;
+import android.util.SparseArray;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.backup.utils.RandomAccessFileUtils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class BackupManagerServiceTest {
+ private static final String PACKAGE_NAME = "some.package.name";
+ private static final String TRANSPORT_NAME = "some.transport.name";
+ private static final String CURRENT_PASSWORD = "current_password";
+ private static final String NEW_PASSWORD = "new_password";
+ private static final String ENCRYPTION_PASSWORD = "encryption_password";
+ private static final CharSequence DATA_MANAGEMENT_LABEL = "data_management_label";
+ private static final String DESTINATION_STRING = "destination_string";
+ private static final String[] PACKAGE_NAMES =
+ new String[]{"some.package.name._1", "some.package.name._2"};
+ private static final String[] TRANSPORTS =
+ new String[]{"some.transport.name._1", "some.transport.name._2"};
+ private static final ComponentName TRANSPORT_COMPONENT_NAME = new ComponentName("package",
+ "class");
+ private static final ComponentName[] TRANSPORT_COMPONENTS = new ComponentName[]{
+ new ComponentName("package1", "class1"),
+ new ComponentName("package2", "class2")
+ };
+ private static final int NON_USER_SYSTEM = UserHandle.USER_SYSTEM + 1;
+ private static final int UNSTARTED_NON_USER_SYSTEM = UserHandle.USER_SYSTEM + 2;
+
+ @UserIdInt
+ private int mUserId;
+ @Mock
+ private UserBackupManagerService mUserBackupManagerService;
+ @Mock
+ private Context mContextMock;
+ @Mock
+ private IBinder mAgentMock;
+ @Mock
+ private ParcelFileDescriptor mParcelFileDescriptorMock;
+ @Mock
+ private IFullBackupRestoreObserver mFullBackupRestoreObserverMock;
+ @Mock
+ private IBackupObserver mBackupObserverMock;
+ @Mock
+ private IBackupManagerMonitor mBackupManagerMonitorMock;
+ @Mock
+ private PrintWriter mPrintWriterMock;
+ @Mock
+ private UserManager mUserManagerMock;
+ @Mock
+ private UserInfo mUserInfoMock;
+
+ private FileDescriptor mFileDescriptorStub = new FileDescriptor();
+
+ private BackupManagerServiceTestable mService;
+ private File mTestDir;
+ private File mSuppressFile;
+ private SparseArray<UserBackupManagerService> mUserServices;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mUserId = UserHandle.USER_SYSTEM;
+
+ mUserServices = new SparseArray<>();
+ mUserServices.append(UserHandle.USER_SYSTEM, mUserBackupManagerService);
+ mUserServices.append(NON_USER_SYSTEM, mUserBackupManagerService);
+
+ when(mUserManagerMock.getUserInfo(UserHandle.USER_SYSTEM)).thenReturn(mUserInfoMock);
+ when(mUserManagerMock.getUserInfo(NON_USER_SYSTEM)).thenReturn(mUserInfoMock);
+ when(mUserManagerMock.getUserInfo(UNSTARTED_NON_USER_SYSTEM)).thenReturn(mUserInfoMock);
+
+ BackupManagerServiceTestable.sCallingUserId = UserHandle.USER_SYSTEM;
+ BackupManagerServiceTestable.sCallingUid = Process.SYSTEM_UID;
+ BackupManagerServiceTestable.sBackupDisabled = false;
+ BackupManagerServiceTestable.sUserManagerMock = mUserManagerMock;
+
+ mTestDir = InstrumentationRegistry.getContext().getFilesDir();
+ mTestDir.mkdirs();
+
+ mSuppressFile = new File(mTestDir, "suppress");
+ BackupManagerServiceTestable.sSuppressFile = mSuppressFile;
+
+ setUpStateFilesForNonSystemUser(NON_USER_SYSTEM);
+ setUpStateFilesForNonSystemUser(UNSTARTED_NON_USER_SYSTEM);
+
+ when(mContextMock.getSystemService(Context.JOB_SCHEDULER_SERVICE))
+ .thenReturn(mock(JobScheduler.class));
+ mService = new BackupManagerServiceTestable(mContextMock, mUserServices);
+ }
+
+ private void setUpStateFilesForNonSystemUser(int userId) {
+ File activatedFile = new File(mTestDir, "activate-" + userId);
+ BackupManagerServiceTestable.sActivatedFiles.append(userId, activatedFile);
+ File rememberActivatedFile = new File(mTestDir, "rem-activate-" + userId);
+ BackupManagerServiceTestable.sRememberActivatedFiles.append(userId, rememberActivatedFile);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mSuppressFile.delete();
+ deleteFiles(BackupManagerServiceTestable.sActivatedFiles);
+ deleteFiles(BackupManagerServiceTestable.sRememberActivatedFiles);
+ }
+
+ private void deleteFiles(SparseArray<File> files) {
+ int numFiles = files.size();
+ for (int i = 0; i < numFiles; i++) {
+ files.valueAt(i).delete();
+ }
+ }
+
+ @Test
+ public void testIsBackupServiceActive_whenBackupsNotDisabledAndSuppressFileDoesNotExist() {
+ assertTrue(mService.isBackupServiceActive(UserHandle.USER_SYSTEM));
+ }
+
+ @Test
+ public void testOnUnlockUser_forNonSystemUserWhenBackupsDisabled_doesNotStartUser() {
+ BackupManagerServiceTestable.sBackupDisabled = true;
+ BackupManagerServiceTestable service =
+ new BackupManagerServiceTestable(mContextMock, new SparseArray<>());
+ ConditionVariable unlocked = new ConditionVariable(false);
+
+ service.onUnlockUser(NON_USER_SYSTEM);
+
+ service.getBackupHandler().post(unlocked::open);
+ unlocked.block();
+ assertNull(service.getUserService(NON_USER_SYSTEM));
+ }
+
+ @Test
+ public void testOnUnlockUser_forSystemUserWhenBackupsDisabled_doesNotStartUser() {
+ BackupManagerServiceTestable.sBackupDisabled = true;
+ BackupManagerServiceTestable service =
+ new BackupManagerServiceTestable(mContextMock, new SparseArray<>());
+ ConditionVariable unlocked = new ConditionVariable(false);
+
+ service.onUnlockUser(UserHandle.USER_SYSTEM);
+
+ service.getBackupHandler().post(unlocked::open);
+ unlocked.block();
+ assertNull(service.getUserService(UserHandle.USER_SYSTEM));
+ }
+
+ @Test
+ public void testOnUnlockUser_whenBackupNotActivated_doesNotStartUser() {
+ BackupManagerServiceTestable.sBackupDisabled = false;
+ BackupManagerServiceTestable service =
+ new BackupManagerServiceTestable(mContextMock, new SparseArray<>());
+ service.setBackupServiceActive(NON_USER_SYSTEM, false);
+ ConditionVariable unlocked = new ConditionVariable(false);
+
+ service.onUnlockUser(NON_USER_SYSTEM);
+
+ service.getBackupHandler().post(unlocked::open);
+ unlocked.block();
+ assertNull(service.getUserService(NON_USER_SYSTEM));
+ }
+
+ @Test
+ public void testIsBackupServiceActive_forSystemUserWhenBackupDisabled_returnsTrue()
+ throws Exception {
+ BackupManagerServiceTestable.sBackupDisabled = true;
+ BackupManagerService backupManagerService =
+ new BackupManagerServiceTestable(mContextMock, mUserServices);
+ backupManagerService.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
+
+ assertFalse(backupManagerService.isBackupServiceActive(UserHandle.USER_SYSTEM));
+ }
+
+ @Test
+ public void testIsBackupServiceActive_forNonSystemUserWhenBackupDisabled_returnsTrue()
+ throws Exception {
+ BackupManagerServiceTestable.sBackupDisabled = true;
+ BackupManagerService backupManagerService =
+ new BackupManagerServiceTestable(mContextMock, mUserServices);
+ backupManagerService.setBackupServiceActive(NON_USER_SYSTEM, true);
+
+ assertFalse(backupManagerService.isBackupServiceActive(NON_USER_SYSTEM));
+ }
+
+ @Test
+ public void isBackupServiceActive_forSystemUser_returnsTrueWhenActivated() throws Exception {
+ mService.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
+
+ assertTrue(mService.isBackupServiceActive(UserHandle.USER_SYSTEM));
+ }
+
+ @Test
+ public void isBackupServiceActive_forSystemUser_returnsFalseWhenDeactivated() throws Exception {
+ mService.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
+
+ assertFalse(mService.isBackupServiceActive(UserHandle.USER_SYSTEM));
+ }
+
+ @Test
+ public void isBackupServiceActive_forNonSystemUser_returnsFalseWhenSystemUserDeactivated()
+ throws Exception {
+ mService.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
+ mService.setBackupServiceActive(NON_USER_SYSTEM, true);
+
+ assertFalse(mService.isBackupServiceActive(NON_USER_SYSTEM));
+ }
+
+ @Test
+ public void isBackupServiceActive_forNonSystemUser_returnsFalseWhenNonSystemUserDeactivated()
+ throws Exception {
+ mService.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
+ // Don't activate non-system user.
+
+ assertFalse(mService.isBackupServiceActive(NON_USER_SYSTEM));
+ }
+
+ @Test
+ public void
+ isBackupServiceActive_forNonSystemUser_returnsTrueWhenSystemAndNonSystemUserActivated()
+ throws Exception {
+ mService.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
+ mService.setBackupServiceActive(NON_USER_SYSTEM, true);
+
+ assertTrue(mService.isBackupServiceActive(NON_USER_SYSTEM));
+ }
+
+ @Test
+ public void
+ isBackupServiceActive_forUnstartedNonSystemUser_returnsTrueWhenSystemAndUserActivated()
+ throws Exception {
+ mService.setBackupServiceActive(UNSTARTED_NON_USER_SYSTEM, true);
+
+ assertTrue(mService.isBackupServiceActive(UNSTARTED_NON_USER_SYSTEM));
+ }
+
+ @Test
+ public void setBackupServiceActive_forSystemUserAndCallerSystemUid_serviceCreated() {
+ BackupManagerServiceTestable.sCallingUid = Process.SYSTEM_UID;
+
+ mService.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
+
+ assertTrue(mService.isBackupServiceActive(UserHandle.USER_SYSTEM));
+ }
+
+ @Test
+ public void setBackupServiceActive_forSystemUserAndCallerRootUid_serviceCreated() {
+ BackupManagerServiceTestable.sCallingUid = Process.ROOT_UID;
+
+ mService.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
+
+ assertTrue(mService.isBackupServiceActive(UserHandle.USER_SYSTEM));
+ }
+
+ @Test
+ public void setBackupServiceActive_forSystemUserAndCallerNonRootNonSystem_throws() {
+ BackupManagerServiceTestable.sCallingUid = Process.FIRST_APPLICATION_UID;
+
+ try {
+ mService.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
+ fail();
+ } catch (SecurityException expected) {
+ }
+ }
+
+ @Test
+ public void setBackupServiceActive_forManagedProfileAndCallerSystemUid_serviceCreated() {
+ when(mUserInfoMock.isManagedProfile()).thenReturn(true);
+ BackupManagerServiceTestable.sCallingUid = Process.SYSTEM_UID;
+
+ mService.setBackupServiceActive(NON_USER_SYSTEM, true);
+
+ assertTrue(mService.isBackupServiceActive(NON_USER_SYSTEM));
+ }
+
+ @Test
+ public void setBackupServiceActive_forManagedProfileAndCallerRootUid_serviceCreated() {
+ when(mUserInfoMock.isManagedProfile()).thenReturn(true);
+ BackupManagerServiceTestable.sCallingUid = Process.ROOT_UID;
+
+ mService.setBackupServiceActive(NON_USER_SYSTEM, true);
+
+ assertTrue(mService.isBackupServiceActive(NON_USER_SYSTEM));
+ }
+
+ @Test
+ public void setBackupServiceActive_forManagedProfileAndCallerNonRootNonSystem_throws() {
+ when(mUserInfoMock.isManagedProfile()).thenReturn(true);
+ BackupManagerServiceTestable.sCallingUid = Process.FIRST_APPLICATION_UID;
+
+ try {
+ mService.setBackupServiceActive(NON_USER_SYSTEM, true);
+ fail();
+ } catch (SecurityException expected) {
+ }
+ }
+
+ @Test
+ public void setBackupServiceActive_forNonSystemUserAndCallerWithoutBackupPermission_throws() {
+ doThrow(new SecurityException())
+ .when(mContextMock)
+ .enforceCallingOrSelfPermission(eq(Manifest.permission.BACKUP), anyString());
+
+ try {
+ mService.setBackupServiceActive(NON_USER_SYSTEM, true);
+ fail();
+ } catch (SecurityException expected) {
+ }
+ }
+
+ @Test
+ public void setBackupServiceActive_forNonSystemUserAndCallerWithoutUserPermission_throws() {
+ doThrow(new SecurityException())
+ .when(mContextMock)
+ .enforceCallingOrSelfPermission(
+ eq(Manifest.permission.INTERACT_ACROSS_USERS_FULL), anyString());
+
+ try {
+ mService.setBackupServiceActive(NON_USER_SYSTEM, true);
+ fail();
+ } catch (SecurityException expected) {
+ }
+ }
+
+ @Test
+ public void setBackupServiceActive_backupDisabled_ignored() {
+ BackupManagerServiceTestable.sBackupDisabled = true;
+ BackupManagerServiceTestable service =
+ new BackupManagerServiceTestable(mContextMock, mUserServices);
+
+ service.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
+
+ assertFalse(service.isBackupServiceActive(UserHandle.USER_SYSTEM));
+ }
+
+ @Test
+ public void setBackupServiceActive_alreadyActive_ignored() {
+ mService.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
+ assertTrue(mService.isBackupServiceActive(UserHandle.USER_SYSTEM));
+
+ mService.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
+ assertTrue(mService.isBackupServiceActive(UserHandle.USER_SYSTEM));
+ }
+
+ @Test
+ public void setBackupServiceActive_makeNonActive_alreadyNonActive_ignored() {
+ mService.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
+ mService.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
+
+ assertFalse(mService.isBackupServiceActive(UserHandle.USER_SYSTEM));
+ }
+
+ @Test
+ public void setBackupServiceActive_makeActive_serviceCreatedAndSuppressFileDeleted() {
+ mService.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
+
+ assertTrue(mService.isBackupServiceActive(UserHandle.USER_SYSTEM));
+ }
+
+ @Test
+ public void setBackupServiceActive_makeNonActive_serviceDeletedAndSuppressFileCreated()
+ throws IOException {
+ assertTrue(mService.isBackupServiceActive(UserHandle.USER_SYSTEM));
+
+ mService.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
+
+ assertFalse(mService.isBackupServiceActive(UserHandle.USER_SYSTEM));
+ }
+
+ @Test
+ public void setBackupActive_nonSystemUser_disabledForSystemUser_ignored() {
+ mService.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
+ mService.setBackupServiceActive(NON_USER_SYSTEM, true);
+
+ assertFalse(mService.isBackupServiceActive(NON_USER_SYSTEM));
+ }
+
+ @Test
+ public void setBackupServiceActive_forOneNonSystemUser_doesNotActivateForAllNonSystemUsers() {
+ int otherUser = NON_USER_SYSTEM + 1;
+ File activateFile = new File(mTestDir, "activate-" + otherUser);
+ BackupManagerServiceTestable.sActivatedFiles.append(otherUser, activateFile);
+ mService.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
+
+ mService.setBackupServiceActive(NON_USER_SYSTEM, true);
+
+ assertTrue(mService.isBackupServiceActive(NON_USER_SYSTEM));
+ assertFalse(mService.isBackupServiceActive(otherUser));
+ activateFile.delete();
+ }
+
+ @Test
+ public void setBackupServiceActive_forNonSystemUser_remembersActivated() {
+
+ mService.setBackupServiceActive(NON_USER_SYSTEM, true);
+
+ assertTrue(RandomAccessFileUtils.readBoolean(
+ BackupManagerServiceTestable.sRememberActivatedFiles.get(NON_USER_SYSTEM), false));
+ }
+
+ @Test
+ public void setBackupServiceActiveFalse_forNonSystemUser_remembersActivated() {
+
+ mService.setBackupServiceActive(NON_USER_SYSTEM, false);
+
+ assertFalse(RandomAccessFileUtils.readBoolean(
+ BackupManagerServiceTestable.sRememberActivatedFiles.get(NON_USER_SYSTEM), true));
+ }
+
+ @Test
+ public void setBackupServiceActiveTwice_forNonSystemUser_remembersLastActivated() {
+ mService.setBackupServiceActive(NON_USER_SYSTEM, true);
+ mService.setBackupServiceActive(NON_USER_SYSTEM, false);
+
+ assertFalse(RandomAccessFileUtils.readBoolean(
+ BackupManagerServiceTestable.sRememberActivatedFiles.get(NON_USER_SYSTEM), true));
+ }
+
+ @Test
+ public void selectBackupTransportAsyncForUser_beforeUserUnlocked_notifiesBackupNotAllowed()
+ throws Exception {
+ mUserServices.clear();
+ CompletableFuture<Integer> future = new CompletableFuture<>();
+ ISelectBackupTransportCallback listener =
+ new ISelectBackupTransportCallback.Stub() {
+ @Override
+ public void onSuccess(String transportName) {
+ future.completeExceptionally(new AssertionError());
+ }
+ @Override
+ public void onFailure(int reason) {
+ future.complete(reason);
+ }
+ };
+
+ mService.selectBackupTransportAsyncForUser(mUserId, TRANSPORT_COMPONENT_NAME, listener);
+
+ assertEquals(BackupManager.ERROR_BACKUP_NOT_ALLOWED, (int) future.get(5, TimeUnit.SECONDS));
+ }
+
+ @Test
+ public void selectBackupTransportAsyncForUser_beforeUserUnlockedWithNullListener_doesNotThrow()
+ throws Exception {
+ mService.selectBackupTransportAsyncForUser(mUserId, TRANSPORT_COMPONENT_NAME, null);
+
+ // No crash.
+ }
+
+ @Test
+ public void
+ selectBackupTransportAsyncForUser_beforeUserUnlockedListenerThrowing_doesNotThrow()
+ throws Exception {
+ ISelectBackupTransportCallback.Stub listener =
+ new ISelectBackupTransportCallback.Stub() {
+ @Override
+ public void onSuccess(String transportName) {}
+ @Override
+ public void onFailure(int reason) throws RemoteException {
+ throw new RemoteException();
+ }
+ };
+
+ mService.selectBackupTransportAsyncForUser(mUserId, TRANSPORT_COMPONENT_NAME, listener);
+
+ // No crash.
+ }
+
+ @Test
+ public void dump_callerDoesNotHavePermission_ignored() {
+ when(mContextMock.checkCallingOrSelfPermission(
+ android.Manifest.permission.DUMP)).thenReturn(
+ PackageManager.PERMISSION_DENIED);
+
+ mService.dump(mFileDescriptorStub, mPrintWriterMock, new String[0]);
+
+ verifyNoMoreInteractions(mUserBackupManagerService);
+ }
+
+ public void testGetUserForAncestralSerialNumber() {
+ BackupManagerServiceTestable.sBackupDisabled = false;
+ BackupManagerService backupManagerService =
+ new BackupManagerServiceTestable(mContextMock, mUserServices);
+ when(mUserBackupManagerService.getAncestralSerialNumber()).thenReturn(11L);
+
+ UserHandle user = backupManagerService.getUserForAncestralSerialNumber(11L);
+
+ assertThat(user).isEqualTo(UserHandle.of(1));
+ }
+
+ public void testGetUserForAncestralSerialNumber_whenDisabled() {
+ BackupManagerServiceTestable.sBackupDisabled = true;
+ BackupManagerService backupManagerService =
+ new BackupManagerServiceTestable(mContextMock, mUserServices);
+ when(mUserBackupManagerService.getAncestralSerialNumber()).thenReturn(11L);
+
+ UserHandle user = backupManagerService.getUserForAncestralSerialNumber(11L);
+
+ assertThat(user).isNull();
+ }
+
+ private static class BackupManagerServiceTestable extends BackupManagerService {
+ static boolean sBackupDisabled = false;
+ static int sCallingUserId = -1;
+ static int sCallingUid = -1;
+ static File sSuppressFile = null;
+ static SparseArray<File> sActivatedFiles = new SparseArray<>();
+ static SparseArray<File> sRememberActivatedFiles = new SparseArray<>();
+ static UserManager sUserManagerMock = null;
+
+ BackupManagerServiceTestable(
+ Context context, SparseArray<UserBackupManagerService> userServices) {
+ super(context, userServices);
+ }
+
+ @Override
+ protected UserManager getUserManager() {
+ return sUserManagerMock;
+ }
+
+ @Override
+ protected boolean isBackupDisabled() {
+ return sBackupDisabled;
+ }
+
+ @Override
+ protected File getSuppressFileForSystemUser() {
+ return sSuppressFile;
+ }
+
+ @Override
+ protected File getRememberActivatedFileForNonSystemUser(int userId) {
+ return sRememberActivatedFiles.get(userId);
+ }
+
+ @Override
+ protected File getActivatedFileForNonSystemUser(int userId) {
+ return sActivatedFiles.get(userId);
+ }
+
+ protected int binderGetCallingUserId() {
+ return sCallingUserId;
+ }
+
+ @Override
+ protected int binderGetCallingUid() {
+ return sCallingUid;
+ }
+
+ @Override
+ protected void postToHandler(Runnable runnable) {
+ runnable.run();
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java b/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
deleted file mode 100644
index 8668a3c..0000000
--- a/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
+++ /dev/null
@@ -1,1116 +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.server.backup;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertNull;
-import static junit.framework.Assert.assertTrue;
-import static junit.framework.Assert.fail;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import android.Manifest;
-import android.annotation.UserIdInt;
-import android.app.backup.BackupManager;
-import android.app.backup.IBackupManagerMonitor;
-import android.app.backup.IBackupObserver;
-import android.app.backup.IFullBackupRestoreObserver;
-import android.app.backup.ISelectBackupTransportCallback;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.UserInfo;
-import android.os.ConditionVariable;
-import android.os.IBinder;
-import android.os.ParcelFileDescriptor;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.platform.test.annotations.Presubmit;
-import android.util.SparseArray;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.server.backup.utils.RandomAccessFileUtils;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.io.File;
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.util.Set;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.TimeUnit;
-
-@SmallTest
-@Presubmit
-@RunWith(AndroidJUnit4.class)
-public class TrampolineTest {
- private static final String PACKAGE_NAME = "some.package.name";
- private static final String TRANSPORT_NAME = "some.transport.name";
- private static final String CURRENT_PASSWORD = "current_password";
- private static final String NEW_PASSWORD = "new_password";
- private static final String ENCRYPTION_PASSWORD = "encryption_password";
- private static final CharSequence DATA_MANAGEMENT_LABEL = "data_management_label";
- private static final String DESTINATION_STRING = "destination_string";
- private static final String[] PACKAGE_NAMES =
- new String[]{"some.package.name._1", "some.package.name._2"};
- private static final String[] TRANSPORTS =
- new String[]{"some.transport.name._1", "some.transport.name._2"};
- private static final ComponentName TRANSPORT_COMPONENT_NAME = new ComponentName("package",
- "class");
- private static final ComponentName[] TRANSPORT_COMPONENTS = new ComponentName[]{
- new ComponentName("package1", "class1"),
- new ComponentName("package2", "class2")
- };
- private static final int NON_USER_SYSTEM = UserHandle.USER_SYSTEM + 1;
- private static final int UNSTARTED_NON_USER_SYSTEM = UserHandle.USER_SYSTEM + 2;
-
- @UserIdInt
- private int mUserId;
- @Mock
- private BackupManagerService mBackupManagerServiceMock;
- @Mock
- private UserBackupManagerService mUserBackupManagerService;
- @Mock
- private Context mContextMock;
- @Mock
- private IBinder mAgentMock;
- @Mock
- private ParcelFileDescriptor mParcelFileDescriptorMock;
- @Mock
- private IFullBackupRestoreObserver mFullBackupRestoreObserverMock;
- @Mock
- private IBackupObserver mBackupObserverMock;
- @Mock
- private IBackupManagerMonitor mBackupManagerMonitorMock;
- @Mock
- private PrintWriter mPrintWriterMock;
- @Mock
- private UserManager mUserManagerMock;
- @Mock
- private UserInfo mUserInfoMock;
-
- private FileDescriptor mFileDescriptorStub = new FileDescriptor();
-
- private TrampolineTestable mTrampoline;
- private File mTestDir;
- private File mSuppressFile;
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
- mUserId = UserHandle.USER_SYSTEM;
-
- SparseArray<UserBackupManagerService> serviceUsers = new SparseArray<>();
- serviceUsers.append(UserHandle.USER_SYSTEM, mUserBackupManagerService);
- serviceUsers.append(NON_USER_SYSTEM, mUserBackupManagerService);
- when(mBackupManagerServiceMock.getUserServices()).thenReturn(serviceUsers);
-
- when(mUserManagerMock.getUserInfo(UserHandle.USER_SYSTEM)).thenReturn(mUserInfoMock);
- when(mUserManagerMock.getUserInfo(NON_USER_SYSTEM)).thenReturn(mUserInfoMock);
- when(mUserManagerMock.getUserInfo(UNSTARTED_NON_USER_SYSTEM)).thenReturn(mUserInfoMock);
-
- TrampolineTestable.sBackupManagerServiceMock = mBackupManagerServiceMock;
- TrampolineTestable.sCallingUserId = UserHandle.USER_SYSTEM;
- TrampolineTestable.sCallingUid = Process.SYSTEM_UID;
- TrampolineTestable.sBackupDisabled = false;
- TrampolineTestable.sUserManagerMock = mUserManagerMock;
-
- mTestDir = InstrumentationRegistry.getContext().getFilesDir();
- mTestDir.mkdirs();
-
- mSuppressFile = new File(mTestDir, "suppress");
- TrampolineTestable.sSuppressFile = mSuppressFile;
-
- setUpStateFilesForNonSystemUser(NON_USER_SYSTEM);
- setUpStateFilesForNonSystemUser(UNSTARTED_NON_USER_SYSTEM);
-
- mTrampoline = new TrampolineTestable(mContextMock);
- }
-
- private void setUpStateFilesForNonSystemUser(int userId) {
- File activatedFile = new File(mTestDir, "activate-" + userId);
- TrampolineTestable.sActivatedFiles.append(userId, activatedFile);
- File rememberActivatedFile = new File(mTestDir, "rem-activate-" + userId);
- TrampolineTestable.sRememberActivatedFiles.append(userId, rememberActivatedFile);
- }
-
- @After
- public void tearDown() throws Exception {
- mSuppressFile.delete();
- deleteFiles(TrampolineTestable.sActivatedFiles);
- deleteFiles(TrampolineTestable.sRememberActivatedFiles);
- }
-
- private void deleteFiles(SparseArray<File> files) {
- int numFiles = files.size();
- for (int i = 0; i < numFiles; i++) {
- files.valueAt(i).delete();
- }
- }
-
- @Test
- public void testIsBackupServiceActive_whenBackupsNotDisabledAndSuppressFileDoesNotExist() {
- assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
- }
-
- @Test
- public void testOnUnlockUser_forNonSystemUserWhenBackupsDisabled_doesNotStartUser() {
- when(mBackupManagerServiceMock.getUserServices()).thenReturn(new SparseArray<>());
- TrampolineTestable.sBackupDisabled = true;
- TrampolineTestable trampoline = new TrampolineTestable(mContextMock);
- ConditionVariable unlocked = new ConditionVariable(false);
-
- trampoline.onUnlockUser(NON_USER_SYSTEM);
-
- trampoline.getBackupHandler().post(unlocked::open);
- unlocked.block();
- assertNull(trampoline.getUserService(NON_USER_SYSTEM));
- }
-
- @Test
- public void testOnUnlockUser_forSystemUserWhenBackupsDisabled_doesNotStartUser() {
- when(mBackupManagerServiceMock.getUserServices()).thenReturn(new SparseArray<>());
- TrampolineTestable.sBackupDisabled = true;
- TrampolineTestable trampoline = new TrampolineTestable(mContextMock);
- ConditionVariable unlocked = new ConditionVariable(false);
-
- trampoline.onUnlockUser(UserHandle.USER_SYSTEM);
-
- trampoline.getBackupHandler().post(unlocked::open);
- unlocked.block();
- assertNull(trampoline.getUserService(UserHandle.USER_SYSTEM));
- }
-
- @Test
- public void testOnUnlockUser_whenBackupNotActivated_doesNotStartUser() {
- when(mBackupManagerServiceMock.getUserServices()).thenReturn(new SparseArray<>());
- TrampolineTestable.sBackupDisabled = false;
- TrampolineTestable trampoline = new TrampolineTestable(mContextMock);
- trampoline.setBackupServiceActive(NON_USER_SYSTEM, false);
- ConditionVariable unlocked = new ConditionVariable(false);
-
- trampoline.onUnlockUser(NON_USER_SYSTEM);
-
- trampoline.getBackupHandler().post(unlocked::open);
- unlocked.block();
- assertNull(trampoline.getUserService(NON_USER_SYSTEM));
- //noinspection unchecked
- verify(mBackupManagerServiceMock, never()).startServiceForUser(
- eq(NON_USER_SYSTEM), any(Set.class));
- }
-
- @Test
- public void testIsBackupServiceActive_forSystemUserWhenBackupDisabled_returnsTrue()
- throws Exception {
- TrampolineTestable.sBackupDisabled = true;
- Trampoline trampoline = new TrampolineTestable(mContextMock);
- trampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
-
- assertFalse(trampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
- }
-
- @Test
- public void testIsBackupServiceActive_forNonSystemUserWhenBackupDisabled_returnsTrue()
- throws Exception {
- TrampolineTestable.sBackupDisabled = true;
- Trampoline trampoline = new TrampolineTestable(mContextMock);
- trampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
-
- assertFalse(trampoline.isBackupServiceActive(NON_USER_SYSTEM));
- }
-
- @Test
- public void isBackupServiceActive_forSystemUser_returnsTrueWhenActivated() throws Exception {
- mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
-
- assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
- }
-
- @Test
- public void isBackupServiceActive_forSystemUser_returnsFalseWhenDeactivated() throws Exception {
- mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
-
- assertFalse(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
- }
-
- @Test
- public void isBackupServiceActive_forNonSystemUser_returnsFalseWhenSystemUserDeactivated()
- throws Exception {
- mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
- mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
-
- assertFalse(mTrampoline.isBackupServiceActive(NON_USER_SYSTEM));
- }
-
- @Test
- public void isBackupServiceActive_forNonSystemUser_returnsFalseWhenNonSystemUserDeactivated()
- throws Exception {
- mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
- // Don't activate non-system user.
-
- assertFalse(mTrampoline.isBackupServiceActive(NON_USER_SYSTEM));
- }
-
- @Test
- public void
- isBackupServiceActive_forNonSystemUser_returnsTrueWhenSystemAndNonSystemUserActivated()
- throws Exception {
- mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
- mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
-
- assertTrue(mTrampoline.isBackupServiceActive(NON_USER_SYSTEM));
- }
-
- @Test
- public void
- isBackupServiceActive_forUnstartedNonSystemUser_returnsTrueWhenSystemAndUserActivated()
- throws Exception {
- mTrampoline.setBackupServiceActive(UNSTARTED_NON_USER_SYSTEM, true);
-
- assertTrue(mTrampoline.isBackupServiceActive(UNSTARTED_NON_USER_SYSTEM));
- }
-
- @Test
- public void setBackupServiceActive_forSystemUserAndCallerSystemUid_serviceCreated() {
- TrampolineTestable.sCallingUid = Process.SYSTEM_UID;
-
- mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
-
- assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
- }
-
- @Test
- public void setBackupServiceActive_forSystemUserAndCallerRootUid_serviceCreated() {
- TrampolineTestable.sCallingUid = Process.ROOT_UID;
-
- mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
-
- assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
- }
-
- @Test
- public void setBackupServiceActive_forSystemUserAndCallerNonRootNonSystem_throws() {
- TrampolineTestable.sCallingUid = Process.FIRST_APPLICATION_UID;
-
- try {
- mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
- fail();
- } catch (SecurityException expected) {
- }
- }
-
- @Test
- public void setBackupServiceActive_forManagedProfileAndCallerSystemUid_serviceCreated() {
- when(mUserInfoMock.isManagedProfile()).thenReturn(true);
- TrampolineTestable.sCallingUid = Process.SYSTEM_UID;
-
- mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
-
- assertTrue(mTrampoline.isBackupServiceActive(NON_USER_SYSTEM));
- }
-
- @Test
- public void setBackupServiceActive_forManagedProfileAndCallerRootUid_serviceCreated() {
- when(mUserInfoMock.isManagedProfile()).thenReturn(true);
- TrampolineTestable.sCallingUid = Process.ROOT_UID;
-
- mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
-
- assertTrue(mTrampoline.isBackupServiceActive(NON_USER_SYSTEM));
- }
-
- @Test
- public void setBackupServiceActive_forManagedProfileAndCallerNonRootNonSystem_throws() {
- when(mUserInfoMock.isManagedProfile()).thenReturn(true);
- TrampolineTestable.sCallingUid = Process.FIRST_APPLICATION_UID;
-
- try {
- mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
- fail();
- } catch (SecurityException expected) {
- }
- }
-
- @Test
- public void setBackupServiceActive_forNonSystemUserAndCallerWithoutBackupPermission_throws() {
- doThrow(new SecurityException())
- .when(mContextMock)
- .enforceCallingOrSelfPermission(eq(Manifest.permission.BACKUP), anyString());
-
- try {
- mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
- fail();
- } catch (SecurityException expected) {
- }
- }
-
- @Test
- public void setBackupServiceActive_forNonSystemUserAndCallerWithoutUserPermission_throws() {
- doThrow(new SecurityException())
- .when(mContextMock)
- .enforceCallingOrSelfPermission(
- eq(Manifest.permission.INTERACT_ACROSS_USERS_FULL), anyString());
-
- try {
- mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
- fail();
- } catch (SecurityException expected) {
- }
- }
-
- @Test
- public void setBackupServiceActive_backupDisabled_ignored() {
- TrampolineTestable.sBackupDisabled = true;
- TrampolineTestable trampoline = new TrampolineTestable(mContextMock);
-
- trampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
-
- assertFalse(trampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
- }
-
- @Test
- public void setBackupServiceActive_alreadyActive_ignored() {
- mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
- assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
-
- mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
- assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
- }
-
- @Test
- public void setBackupServiceActive_makeNonActive_alreadyNonActive_ignored() {
- mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
- mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
-
- assertFalse(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
- }
-
- @Test
- public void setBackupServiceActive_makeActive_serviceCreatedAndSuppressFileDeleted() {
- mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
-
- assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
- }
-
- @Test
- public void setBackupServiceActive_makeNonActive_serviceDeletedAndSuppressFileCreated()
- throws IOException {
- assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
-
- mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
-
- assertFalse(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
- }
-
- @Test
- public void setBackupActive_nonSystemUser_disabledForSystemUser_ignored() {
- mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
- mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
-
- assertFalse(mTrampoline.isBackupServiceActive(NON_USER_SYSTEM));
- }
-
- @Test
- public void setBackupServiceActive_forOneNonSystemUser_doesNotActivateForAllNonSystemUsers() {
- int otherUser = NON_USER_SYSTEM + 1;
- File activateFile = new File(mTestDir, "activate-" + otherUser);
- TrampolineTestable.sActivatedFiles.append(otherUser, activateFile);
- mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
-
- mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
-
- assertTrue(mTrampoline.isBackupServiceActive(NON_USER_SYSTEM));
- assertFalse(mTrampoline.isBackupServiceActive(otherUser));
- activateFile.delete();
- }
-
- @Test
- public void setBackupServiceActive_forNonSystemUser_remembersActivated() {
-
- mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
-
- assertTrue(RandomAccessFileUtils.readBoolean(
- TrampolineTestable.sRememberActivatedFiles.get(NON_USER_SYSTEM), false));
- }
-
- @Test
- public void setBackupServiceActiveFalse_forNonSystemUser_remembersActivated() {
-
- mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, false);
-
- assertFalse(RandomAccessFileUtils.readBoolean(
- TrampolineTestable.sRememberActivatedFiles.get(NON_USER_SYSTEM), true));
- }
-
- @Test
- public void setBackupServiceActiveTwice_forNonSystemUser_remembersLastActivated() {
- mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
- mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, false);
-
- assertFalse(RandomAccessFileUtils.readBoolean(
- TrampolineTestable.sRememberActivatedFiles.get(NON_USER_SYSTEM), true));
- }
-
- @Test
- public void dataChangedForUser_forwarded() throws Exception {
- mTrampoline.dataChangedForUser(mUserId, PACKAGE_NAME);
-
- verify(mBackupManagerServiceMock).dataChanged(mUserId, PACKAGE_NAME);
- }
-
- @Test
- public void dataChanged_forwarded() throws Exception {
- TrampolineTestable.sCallingUserId = mUserId;
-
- mTrampoline.dataChanged(PACKAGE_NAME);
-
- verify(mBackupManagerServiceMock).dataChanged(mUserId, PACKAGE_NAME);
- }
-
- @Test
- public void clearBackupDataForUser_forwarded() throws Exception {
-
- mTrampoline.clearBackupDataForUser(mUserId, TRANSPORT_NAME, PACKAGE_NAME);
-
- verify(mBackupManagerServiceMock).clearBackupData(mUserId, TRANSPORT_NAME, PACKAGE_NAME);
- }
-
- @Test
- public void clearBackupData_forwarded() throws Exception {
- TrampolineTestable.sCallingUserId = mUserId;
-
- mTrampoline.clearBackupData(TRANSPORT_NAME, PACKAGE_NAME);
-
- verify(mBackupManagerServiceMock).clearBackupData(mUserId, TRANSPORT_NAME, PACKAGE_NAME);
- }
-
- @Test
- public void agentConnectedForUser_forwarded() throws Exception {
-
- mTrampoline.agentConnectedForUser(mUserId, PACKAGE_NAME, mAgentMock);
-
- verify(mBackupManagerServiceMock).agentConnected(mUserId, PACKAGE_NAME, mAgentMock);
- }
-
- @Test
- public void agentConnected_forwarded() throws Exception {
- TrampolineTestable.sCallingUserId = mUserId;
-
- mTrampoline.agentConnected(PACKAGE_NAME, mAgentMock);
-
- verify(mBackupManagerServiceMock).agentConnected(mUserId, PACKAGE_NAME, mAgentMock);
- }
-
- @Test
- public void agentDisconnectedForUser_forwarded() throws Exception {
-
- mTrampoline.agentDisconnectedForUser(mUserId, PACKAGE_NAME);
-
- verify(mBackupManagerServiceMock).agentDisconnected(mUserId, PACKAGE_NAME);
- }
-
- @Test
- public void agentDisconnected_forwarded() throws Exception {
- TrampolineTestable.sCallingUserId = mUserId;
-
- mTrampoline.agentDisconnected(PACKAGE_NAME);
-
- verify(mBackupManagerServiceMock).agentDisconnected(mUserId, PACKAGE_NAME);
- }
-
- @Test
- public void restoreAtInstallForUser_forwarded() throws Exception {
-
- mTrampoline.restoreAtInstallForUser(mUserId, PACKAGE_NAME, 123);
-
- verify(mBackupManagerServiceMock).restoreAtInstall(mUserId, PACKAGE_NAME, 123);
- }
-
- @Test
- public void restoreAtInstall_forwarded() throws Exception {
- TrampolineTestable.sCallingUserId = mUserId;
-
- mTrampoline.restoreAtInstall(PACKAGE_NAME, 123);
-
- verify(mBackupManagerServiceMock).restoreAtInstall(mUserId, PACKAGE_NAME, 123);
- }
-
- @Test
- public void setBackupEnabledForUser_forwarded() throws Exception {
-
- mTrampoline.setBackupEnabledForUser(mUserId, true);
-
- verify(mBackupManagerServiceMock).setBackupEnabled(mUserId, true);
- }
-
- @Test
- public void setBackupEnabled_forwardedToCallingUserId() throws Exception {
- TrampolineTestable.sCallingUserId = mUserId;
-
- mTrampoline.setBackupEnabled(true);
-
- verify(mBackupManagerServiceMock).setBackupEnabled(mUserId, true);
- }
-
- @Test
- public void setAutoRestoreForUser_forwarded() throws Exception {
-
- mTrampoline.setAutoRestoreForUser(mUserId, true);
-
- verify(mBackupManagerServiceMock).setAutoRestore(mUserId, true);
- }
-
- @Test
- public void setAutoRestore_forwarded() throws Exception {
- TrampolineTestable.sCallingUserId = mUserId;
-
- mTrampoline.setAutoRestore(true);
-
- verify(mBackupManagerServiceMock).setAutoRestore(mUserId, true);
- }
-
- @Test
- public void isBackupEnabledForUser_forwarded() throws Exception {
-
- mTrampoline.isBackupEnabledForUser(mUserId);
-
- verify(mBackupManagerServiceMock).isBackupEnabled(mUserId);
- }
-
- @Test
- public void isBackupEnabled_forwardedToCallingUserId() throws Exception {
- TrampolineTestable.sCallingUserId = mUserId;
-
- mTrampoline.isBackupEnabled();
-
- verify(mBackupManagerServiceMock).isBackupEnabled(mUserId);
- }
-
- @Test
- public void setBackupPassword_forwarded() throws Exception {
- mTrampoline.setBackupPassword(CURRENT_PASSWORD, NEW_PASSWORD);
- verify(mBackupManagerServiceMock).setBackupPassword(CURRENT_PASSWORD, NEW_PASSWORD);
- }
-
- @Test
- public void hasBackupPassword_forwarded() throws Exception {
- mTrampoline.hasBackupPassword();
- verify(mBackupManagerServiceMock).hasBackupPassword();
- }
-
- @Test
- public void backupNowForUser_forwarded() throws Exception {
-
- mTrampoline.backupNowForUser(mUserId);
-
- verify(mBackupManagerServiceMock).backupNow(mUserId);
- }
-
- @Test
- public void backupNow_forwardedToCallingUserId() throws Exception {
- TrampolineTestable.sCallingUserId = mUserId;
-
- mTrampoline.backupNow();
-
- verify(mBackupManagerServiceMock).backupNow(mUserId);
- }
-
- @Test
- public void adbBackup_forwarded() throws Exception {
- mTrampoline.adbBackup(mUserId, mParcelFileDescriptorMock, true, true,
- true, true, true, true, true, true,
- PACKAGE_NAMES);
- verify(mBackupManagerServiceMock).adbBackup(mUserId, mParcelFileDescriptorMock, true,
- true, true, true, true, true, true, true, PACKAGE_NAMES);
- }
-
- @Test
- public void fullTransportBackupForUser_forwarded() throws Exception {
-
- mTrampoline.fullTransportBackupForUser(mUserId, PACKAGE_NAMES);
-
- verify(mBackupManagerServiceMock).fullTransportBackup(mUserId, PACKAGE_NAMES);
- }
-
- @Test
- public void adbRestore_forwarded() throws Exception {
- mTrampoline.adbRestore(mUserId, mParcelFileDescriptorMock);
- verify(mBackupManagerServiceMock).adbRestore(mUserId, mParcelFileDescriptorMock);
- }
-
- @Test
- public void acknowledgeFullBackupOrRestoreForUser_forwarded() throws Exception {
-
- mTrampoline.acknowledgeFullBackupOrRestoreForUser(
- mUserId,
- 123,
- true,
- CURRENT_PASSWORD,
- ENCRYPTION_PASSWORD,
- mFullBackupRestoreObserverMock);
-
- verify(mBackupManagerServiceMock)
- .acknowledgeAdbBackupOrRestore(
- mUserId,
- 123,
- true,
- CURRENT_PASSWORD,
- ENCRYPTION_PASSWORD,
- mFullBackupRestoreObserverMock);
- }
-
- @Test
- public void acknowledgeFullBackupOrRestore_forwarded() throws Exception {
- TrampolineTestable.sCallingUserId = mUserId;
-
- mTrampoline.acknowledgeFullBackupOrRestore(123, true, CURRENT_PASSWORD, ENCRYPTION_PASSWORD,
- mFullBackupRestoreObserverMock);
-
- verify(mBackupManagerServiceMock)
- .acknowledgeAdbBackupOrRestore(
- mUserId,
- 123,
- true,
- CURRENT_PASSWORD,
- ENCRYPTION_PASSWORD,
- mFullBackupRestoreObserverMock);
- }
-
- @Test
- public void getCurrentTransportForUser_forwarded() throws Exception {
- when(mBackupManagerServiceMock.getCurrentTransport(mUserId)).thenReturn(TRANSPORT_NAME);
-
- assertEquals(TRANSPORT_NAME, mTrampoline.getCurrentTransportForUser(mUserId));
- verify(mBackupManagerServiceMock).getCurrentTransport(mUserId);
- }
-
- @Test
- public void getCurrentTransport_forwarded() throws Exception {
- TrampolineTestable.sCallingUserId = mUserId;
- when(mBackupManagerServiceMock.getCurrentTransport(mUserId)).thenReturn(TRANSPORT_NAME);
-
- assertEquals(TRANSPORT_NAME, mTrampoline.getCurrentTransport());
- verify(mBackupManagerServiceMock).getCurrentTransport(mUserId);
- }
-
- @Test
- public void listAllTransportsForUser_forwarded() throws Exception {
- when(mBackupManagerServiceMock.listAllTransports(mUserId)).thenReturn(TRANSPORTS);
-
- assertEquals(TRANSPORTS, mTrampoline.listAllTransportsForUser(mUserId));
- verify(mBackupManagerServiceMock).listAllTransports(mUserId);
- }
-
-
- @Test
- public void listAllTransports_forwarded() throws Exception {
- TrampolineTestable.sCallingUserId = mUserId;
- when(mBackupManagerServiceMock.listAllTransports(mUserId)).thenReturn(TRANSPORTS);
-
- assertEquals(TRANSPORTS, mTrampoline.listAllTransports());
- verify(mBackupManagerServiceMock).listAllTransports(mUserId);
- }
-
- @Test
- public void listAllTransportComponentsForUser_forwarded() throws Exception {
- when(mBackupManagerServiceMock.listAllTransportComponents(mUserId)).thenReturn(
- TRANSPORT_COMPONENTS);
-
- assertEquals(TRANSPORT_COMPONENTS, mTrampoline.listAllTransportComponentsForUser(mUserId));
- verify(mBackupManagerServiceMock).listAllTransportComponents(mUserId);
- }
-
- @Test
- public void updateTransportAttributesForUser_forwarded() {
- mTrampoline.updateTransportAttributesForUser(
- mUserId,
- TRANSPORT_COMPONENT_NAME,
- TRANSPORT_NAME,
- null,
- "Transport Destination",
- null,
- "Data Management");
-
- verify(mBackupManagerServiceMock)
- .updateTransportAttributes(
- mUserId,
- TRANSPORT_COMPONENT_NAME,
- TRANSPORT_NAME,
- null,
- "Transport Destination",
- null,
- "Data Management");
- }
-
- @Test
- public void selectBackupTransportForUser_forwarded() throws Exception {
-
- mTrampoline.selectBackupTransportForUser(mUserId, TRANSPORT_NAME);
-
- verify(mBackupManagerServiceMock).selectBackupTransport(mUserId, TRANSPORT_NAME);
- }
-
- @Test
- public void selectBackupTransport_forwarded() throws Exception {
- TrampolineTestable.sCallingUserId = mUserId;
-
- mTrampoline.selectBackupTransport(TRANSPORT_NAME);
-
- verify(mBackupManagerServiceMock).selectBackupTransport(mUserId, TRANSPORT_NAME);
- }
-
- @Test
- public void selectBackupTransportAsyncForUser_beforeUserUnlocked_notifiesBackupNotAllowed()
- throws Exception {
- when(mBackupManagerServiceMock.getUserServices()).thenReturn(new SparseArray<>());
- CompletableFuture<Integer> future = new CompletableFuture<>();
- ISelectBackupTransportCallback listener =
- new ISelectBackupTransportCallback.Stub() {
- @Override
- public void onSuccess(String transportName) {
- future.completeExceptionally(new AssertionError());
- }
- @Override
- public void onFailure(int reason) {
- future.complete(reason);
- }
- };
-
- mTrampoline.selectBackupTransportAsyncForUser(mUserId, TRANSPORT_COMPONENT_NAME, listener);
-
- assertEquals(BackupManager.ERROR_BACKUP_NOT_ALLOWED, (int) future.get(5, TimeUnit.SECONDS));
- }
-
- @Test
- public void selectBackupTransportAsyncForUser_beforeUserUnlockedWithNullListener_doesNotThrow()
- throws Exception {
- mTrampoline.selectBackupTransportAsyncForUser(mUserId, TRANSPORT_COMPONENT_NAME, null);
-
- // No crash.
- }
-
- @Test
- public void
- selectBackupTransportAsyncForUser_beforeUserUnlockedWithThrowingListener_doesNotThrow()
- throws Exception {
- ISelectBackupTransportCallback.Stub listener =
- new ISelectBackupTransportCallback.Stub() {
- @Override
- public void onSuccess(String transportName) {}
- @Override
- public void onFailure(int reason) throws RemoteException {
- throw new RemoteException();
- }
- };
-
- mTrampoline.selectBackupTransportAsyncForUser(mUserId, TRANSPORT_COMPONENT_NAME, listener);
-
- // No crash.
- }
-
- @Test
- public void selectBackupTransportAsyncForUser_forwarded() throws Exception {
-
- mTrampoline.selectBackupTransportAsyncForUser(mUserId, TRANSPORT_COMPONENT_NAME, null);
-
- verify(mBackupManagerServiceMock)
- .selectBackupTransportAsync(mUserId, TRANSPORT_COMPONENT_NAME, null);
- }
-
- @Test
- public void getConfigurationIntentForUser_forwarded() throws Exception {
- Intent configurationIntentStub = new Intent();
- when(mBackupManagerServiceMock.getConfigurationIntent(mUserId, TRANSPORT_NAME)).thenReturn(
- configurationIntentStub);
-
- assertEquals(
- configurationIntentStub,
- mTrampoline.getConfigurationIntentForUser(mUserId, TRANSPORT_NAME));
- verify(mBackupManagerServiceMock).getConfigurationIntent(mUserId, TRANSPORT_NAME);
- }
-
- @Test
- public void getConfigurationIntent_forwarded() throws Exception {
- TrampolineTestable.sCallingUserId = mUserId;
- Intent configurationIntentStub = new Intent();
- when(mBackupManagerServiceMock.getConfigurationIntent(mUserId, TRANSPORT_NAME)).thenReturn(
- configurationIntentStub);
-
- assertEquals(configurationIntentStub, mTrampoline.getConfigurationIntent(TRANSPORT_NAME));
- verify(mBackupManagerServiceMock).getConfigurationIntent(mUserId, TRANSPORT_NAME);
- }
-
- @Test
- public void getDestinationStringForUser_forwarded() throws Exception {
- when(mBackupManagerServiceMock.getDestinationString(mUserId, TRANSPORT_NAME)).thenReturn(
- DESTINATION_STRING);
-
- assertEquals(
- DESTINATION_STRING,
- mTrampoline.getDestinationStringForUser(mUserId, TRANSPORT_NAME));
- verify(mBackupManagerServiceMock).getDestinationString(mUserId, TRANSPORT_NAME);
- }
-
- @Test
- public void getDestinationString_forwarded() throws Exception {
- TrampolineTestable.sCallingUserId = mUserId;
- when(mBackupManagerServiceMock.getDestinationString(mUserId, TRANSPORT_NAME)).thenReturn(
- DESTINATION_STRING);
-
- assertEquals(DESTINATION_STRING, mTrampoline.getDestinationString(TRANSPORT_NAME));
- verify(mBackupManagerServiceMock).getDestinationString(mUserId, TRANSPORT_NAME);
- }
-
- @Test
- public void getDataManagementIntentForUser_forwarded() throws Exception {
- Intent dataManagementIntent = new Intent();
- when(mBackupManagerServiceMock.getDataManagementIntent(mUserId, TRANSPORT_NAME)).thenReturn(
- dataManagementIntent);
-
- assertEquals(
- dataManagementIntent,
- mTrampoline.getDataManagementIntentForUser(mUserId, TRANSPORT_NAME));
- verify(mBackupManagerServiceMock).getDataManagementIntent(mUserId, TRANSPORT_NAME);
- }
-
- @Test
- public void getDataManagementIntent_forwarded() throws Exception {
- TrampolineTestable.sCallingUserId = mUserId;
- Intent dataManagementIntent = new Intent();
- when(mBackupManagerServiceMock.getDataManagementIntent(mUserId, TRANSPORT_NAME)).thenReturn(
- dataManagementIntent);
-
- assertEquals(dataManagementIntent, mTrampoline.getDataManagementIntent(TRANSPORT_NAME));
- verify(mBackupManagerServiceMock).getDataManagementIntent(mUserId, TRANSPORT_NAME);
- }
-
- @Test
- public void getDataManagementLabelForUser_forwarded() throws Exception {
- when(mBackupManagerServiceMock.getDataManagementLabel(mUserId, TRANSPORT_NAME)).thenReturn(
- DATA_MANAGEMENT_LABEL);
-
- assertEquals(
- DATA_MANAGEMENT_LABEL,
- mTrampoline.getDataManagementLabelForUser(mUserId, TRANSPORT_NAME));
- verify(mBackupManagerServiceMock).getDataManagementLabel(mUserId, TRANSPORT_NAME);
- }
-
- @Test
- public void beginRestoreSessionForUser_forwarded() throws Exception {
-
- mTrampoline.beginRestoreSessionForUser(mUserId, PACKAGE_NAME, TRANSPORT_NAME);
-
- verify(mBackupManagerServiceMock)
- .beginRestoreSession(mUserId, PACKAGE_NAME, TRANSPORT_NAME);
- }
-
- @Test
- public void opComplete_forwarded() throws Exception {
- TrampolineTestable.sCallingUserId = mUserId;
-
- mTrampoline.opComplete(1, 2);
-
- verify(mBackupManagerServiceMock).opComplete(mUserId, 1, 2);
- }
-
- @Test
- public void getAvailableRestoreTokenForUser_forwarded() {
- when(mBackupManagerServiceMock.getAvailableRestoreToken(mUserId, PACKAGE_NAME))
- .thenReturn(123L);
-
- assertEquals(123, mTrampoline.getAvailableRestoreTokenForUser(mUserId, PACKAGE_NAME));
- verify(mBackupManagerServiceMock).getAvailableRestoreToken(mUserId, PACKAGE_NAME);
- }
-
- @Test
- public void isAppEligibleForBackupForUser_forwarded() {
- when(mBackupManagerServiceMock.isAppEligibleForBackup(mUserId, PACKAGE_NAME))
- .thenReturn(true);
-
- assertTrue(mTrampoline.isAppEligibleForBackupForUser(mUserId, PACKAGE_NAME));
- verify(mBackupManagerServiceMock).isAppEligibleForBackup(mUserId, PACKAGE_NAME);
- }
-
- @Test
- public void requestBackupForUser_forwarded() throws Exception {
- when(mBackupManagerServiceMock.requestBackup(mUserId, PACKAGE_NAMES,
- mBackupObserverMock, mBackupManagerMonitorMock, 123)).thenReturn(456);
-
- assertEquals(456, mTrampoline.requestBackupForUser(mUserId, PACKAGE_NAMES,
- mBackupObserverMock, mBackupManagerMonitorMock, 123));
- verify(mBackupManagerServiceMock).requestBackup(mUserId, PACKAGE_NAMES,
- mBackupObserverMock, mBackupManagerMonitorMock, 123);
- }
-
- @Test
- public void requestBackup_forwardedToCallingUserId() throws Exception {
- TrampolineTestable.sCallingUserId = mUserId;
- when(mBackupManagerServiceMock.requestBackup(mUserId, PACKAGE_NAMES,
- mBackupObserverMock, mBackupManagerMonitorMock, 123)).thenReturn(456);
-
- assertEquals(456, mTrampoline.requestBackup(PACKAGE_NAMES,
- mBackupObserverMock, mBackupManagerMonitorMock, 123));
- verify(mBackupManagerServiceMock).requestBackup(mUserId, PACKAGE_NAMES,
- mBackupObserverMock, mBackupManagerMonitorMock, 123);
- }
-
- @Test
- public void cancelBackupsForUser_forwarded() throws Exception {
-
- mTrampoline.cancelBackupsForUser(mUserId);
-
- verify(mBackupManagerServiceMock).cancelBackups(mUserId);
- }
-
- @Test
- public void cancelBackups_forwardedToCallingUserId() throws Exception {
- TrampolineTestable.sCallingUserId = mUserId;
-
- mTrampoline.cancelBackups();
-
- verify(mBackupManagerServiceMock).cancelBackups(mUserId);
- }
-
- @Test
- public void beginFullBackup_forwarded() throws Exception {
- FullBackupJob fullBackupJob = new FullBackupJob();
- when(mBackupManagerServiceMock.beginFullBackup(mUserId, fullBackupJob)).thenReturn(true);
-
- assertTrue(mTrampoline.beginFullBackup(mUserId, fullBackupJob));
- verify(mBackupManagerServiceMock).beginFullBackup(mUserId, fullBackupJob);
- }
-
- @Test
- public void endFullBackup_forwarded() {
- mTrampoline.endFullBackup(mUserId);
- verify(mBackupManagerServiceMock).endFullBackup(mUserId);
- }
-
- @Test
- public void dump_callerDoesNotHavePermission_ignored() {
- when(mContextMock.checkCallingOrSelfPermission(
- android.Manifest.permission.DUMP)).thenReturn(
- PackageManager.PERMISSION_DENIED);
-
- mTrampoline.dump(mFileDescriptorStub, mPrintWriterMock, new String[0]);
-
- verifyNoMoreInteractions(mBackupManagerServiceMock);
- }
-
- @Test
- public void dump_callerHasPermission_forwarded() {
- when(mContextMock.checkCallingOrSelfPermission(
- android.Manifest.permission.DUMP)).thenReturn(
- PackageManager.PERMISSION_GRANTED);
-
- mTrampoline.dump(mFileDescriptorStub, mPrintWriterMock, null);
-
- verify(mBackupManagerServiceMock).dump(mFileDescriptorStub, mPrintWriterMock, null);
- }
-
- public void testGetUserForAncestralSerialNumber() {
- TrampolineTestable.sBackupDisabled = false;
- Trampoline trampoline = new TrampolineTestable(mContextMock);
-
- trampoline.getUserForAncestralSerialNumber(0L);
- verify(mBackupManagerServiceMock).getUserForAncestralSerialNumber(anyInt());
- }
-
- public void testGetUserForAncestralSerialNumber_whenDisabled() {
- TrampolineTestable.sBackupDisabled = true;
- Trampoline trampoline = new TrampolineTestable(mContextMock);
-
- trampoline.getUserForAncestralSerialNumber(0L);
- verify(mBackupManagerServiceMock, never()).getUserForAncestralSerialNumber(anyInt());
- }
-
- private static class TrampolineTestable extends Trampoline {
- static boolean sBackupDisabled = false;
- static int sCallingUserId = -1;
- static int sCallingUid = -1;
- static BackupManagerService sBackupManagerServiceMock = null;
- static File sSuppressFile = null;
- static SparseArray<File> sActivatedFiles = new SparseArray<>();
- static SparseArray<File> sRememberActivatedFiles = new SparseArray<>();
- static UserManager sUserManagerMock = null;
-
- TrampolineTestable(Context context) {
- super(context);
- mService = sBackupManagerServiceMock;
- }
-
- @Override
- protected UserManager getUserManager() {
- return sUserManagerMock;
- }
-
- @Override
- protected boolean isBackupDisabled() {
- return sBackupDisabled;
- }
-
- @Override
- protected File getSuppressFileForSystemUser() {
- return sSuppressFile;
- }
-
- @Override
- protected File getRememberActivatedFileForNonSystemUser(int userId) {
- return sRememberActivatedFiles.get(userId);
- }
-
- @Override
- protected File getActivatedFileForNonSystemUser(int userId) {
- return sActivatedFiles.get(userId);
- }
-
- protected int binderGetCallingUserId() {
- return sCallingUserId;
- }
-
- @Override
- protected int binderGetCallingUid() {
- return sCallingUid;
- }
-
- @Override
- protected void postToHandler(Runnable runnable) {
- runnable.run();
- }
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
new file mode 100644
index 0000000..ccf3a90
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
@@ -0,0 +1,748 @@
+/*
+ * 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.biometrics;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.TestCase.assertNotNull;
+
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.AppOpsManager;
+import android.app.IActivityManager;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.hardware.biometrics.BiometricAuthenticator;
+import android.hardware.biometrics.BiometricConstants;
+import android.hardware.biometrics.BiometricPrompt;
+import android.hardware.biometrics.IBiometricService;
+import android.hardware.biometrics.IBiometricServiceReceiver;
+import android.hardware.biometrics.IBiometricServiceReceiverInternal;
+import android.hardware.face.FaceManager;
+import android.hardware.face.IFaceService;
+import android.hardware.fingerprint.FingerprintManager;
+import android.hardware.fingerprint.IFingerprintService;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.security.KeyStore;
+
+import com.android.internal.R;
+import com.android.internal.statusbar.IStatusBarService;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.List;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+
+@SmallTest
+public class BiometricServiceTest {
+
+ private static final String TAG = "BiometricServiceTest";
+
+ private static final String TEST_PACKAGE_NAME = "test_package";
+
+ private static final String ERROR_HW_UNAVAILABLE = "hw_unavailable";
+ private static final String ERROR_NOT_RECOGNIZED = "not_recognized";
+ private static final String ERROR_TIMEOUT = "error_timeout";
+ private static final String ERROR_CANCELED = "error_canceled";
+ private static final String ERROR_UNABLE_TO_PROCESS = "error_unable_to_process";
+ private static final String ERROR_USER_CANCELED = "error_user_canceled";
+
+ private static final String FINGERPRINT_ACQUIRED_SENSOR_DIRTY = "sensor_dirty";
+
+ private BiometricService mBiometricService;
+
+ @Mock
+ private Context mContext;
+ @Mock
+ private ContentResolver mContentResolver;
+ @Mock
+ private Resources mResources;
+ @Mock
+ private PackageManager mPackageManager;
+ @Mock
+ private AppOpsManager mAppOpsManager;
+ @Mock
+ IBiometricServiceReceiver mReceiver1;
+ @Mock
+ IBiometricServiceReceiver mReceiver2;
+ @Mock
+ FingerprintManager mFingerprintManager;
+ @Mock
+ FaceManager mFaceManager;
+
+ private static class MockInjector extends BiometricService.Injector {
+ @Override
+ IActivityManager getActivityManagerService() {
+ return mock(IActivityManager.class);
+ }
+
+ @Override
+ IStatusBarService getStatusBarService() {
+ return mock(IStatusBarService.class);
+ }
+
+ @Override
+ IFingerprintService getFingerprintService() {
+ return mock(IFingerprintService.class);
+ }
+
+ @Override
+ IFaceService getFaceService() {
+ return mock(IFaceService.class);
+ }
+
+ @Override
+ BiometricService.SettingObserver getSettingObserver(Context context, Handler handler,
+ List<BiometricService.EnabledOnKeyguardCallback> callbacks) {
+ return mock(BiometricService.SettingObserver.class);
+ }
+
+ @Override
+ KeyStore getKeyStore() {
+ return mock(KeyStore.class);
+ }
+
+ @Override
+ boolean isDebugEnabled(Context context, int userId) {
+ return false;
+ }
+
+ @Override
+ void publishBinderService(BiometricService service, IBiometricService.Stub impl) {
+ // no-op for test
+ }
+ }
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ when(mContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOpsManager);
+ when(mContext.getSystemService(Context.FINGERPRINT_SERVICE))
+ .thenReturn(mFingerprintManager);
+ when(mContext.getSystemService(Context.FACE_SERVICE)).thenReturn(mFaceManager);
+ when(mContext.getContentResolver()).thenReturn(mContentResolver);
+ when(mContext.getResources()).thenReturn(mResources);
+
+ when(mResources.getString(R.string.biometric_error_hw_unavailable))
+ .thenReturn(ERROR_HW_UNAVAILABLE);
+ when(mResources.getString(R.string.biometric_not_recognized))
+ .thenReturn(ERROR_NOT_RECOGNIZED);
+ when(mResources.getString(R.string.biometric_error_user_canceled))
+ .thenReturn(ERROR_USER_CANCELED);
+ }
+
+ @Test
+ public void testAuthenticate_withoutHardware_returnsErrorHardwareNotPresent() throws Exception {
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT))
+ .thenReturn(false);
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_IRIS)).thenReturn(false);
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(false);
+
+ mBiometricService = new BiometricService(mContext, new MockInjector());
+ mBiometricService.onStart();
+
+ invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */);
+ waitForIdle();
+ verify(mReceiver1).onError(
+ eq(BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT), eq(ERROR_HW_UNAVAILABLE));
+ }
+
+ @Test
+ public void testAuthenticate_withoutEnrolled_returnsErrorNoBiometrics() throws Exception {
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)).thenReturn(true);
+ when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+
+ mBiometricService = new BiometricService(mContext, new MockInjector());
+ mBiometricService.onStart();
+
+ invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */);
+ waitForIdle();
+ verify(mReceiver1).onError(
+ eq(BiometricConstants.BIOMETRIC_ERROR_NO_BIOMETRICS), any());
+ }
+
+ @Test
+ public void testAuthenticate_whenHalIsDead_returnsErrorHardwareUnavailable() throws Exception {
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)).thenReturn(true);
+ when(mFingerprintManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
+ when(mFingerprintManager.isHardwareDetected()).thenReturn(false);
+
+ mBiometricService = new BiometricService(mContext, new MockInjector());
+ mBiometricService.onStart();
+
+ invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */);
+ waitForIdle();
+ verify(mReceiver1).onError(
+ eq(BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE), eq(ERROR_HW_UNAVAILABLE));
+ }
+
+ @Test
+ public void testAuthenticateFace_respectsUserSetting()
+ throws Exception {
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(true);
+ when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
+ when(mFaceManager.isHardwareDetected()).thenReturn(true);
+
+ mBiometricService = new BiometricService(mContext, new MockInjector());
+ mBiometricService.onStart();
+
+ // Disabled in user settings receives onError
+ when(mBiometricService.mSettingObserver.getFaceEnabledForApps(anyInt())).thenReturn(false);
+ invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */);
+ waitForIdle();
+ verify(mReceiver1).onError(
+ eq(BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE), eq(ERROR_HW_UNAVAILABLE));
+
+ // Enrolled, not disabled in settings, user requires confirmation in settings
+ resetReceiver();
+ when(mBiometricService.mSettingObserver.getFaceEnabledForApps(anyInt())).thenReturn(true);
+ when(mBiometricService.mSettingObserver.getFaceAlwaysRequireConfirmation(anyInt()))
+ .thenReturn(true);
+ invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */);
+ waitForIdle();
+ verify(mReceiver1, never()).onError(anyInt(), any(String.class));
+ verify(mBiometricService.mFaceService).prepareForAuthentication(
+ eq(true) /* requireConfirmation */,
+ any(IBinder.class),
+ anyLong() /* sessionId */,
+ anyInt() /* userId */,
+ any(IBiometricServiceReceiverInternal.class),
+ anyString() /* opPackageName */,
+ anyInt() /* cookie */,
+ anyInt() /* callingUid */,
+ anyInt() /* callingPid */,
+ anyInt() /* callingUserId */);
+
+ // Enrolled, not disabled in settings, user doesn't require confirmation in settings
+ resetReceiver();
+ when(mBiometricService.mSettingObserver.getFaceAlwaysRequireConfirmation(anyInt()))
+ .thenReturn(false);
+ invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */);
+ waitForIdle();
+ verify(mBiometricService.mFaceService).prepareForAuthentication(
+ eq(false) /* requireConfirmation */,
+ any(IBinder.class),
+ anyLong() /* sessionId */,
+ anyInt() /* userId */,
+ any(IBiometricServiceReceiverInternal.class),
+ anyString() /* opPackageName */,
+ anyInt() /* cookie */,
+ anyInt() /* callingUid */,
+ anyInt() /* callingPid */,
+ anyInt() /* callingUserId */);
+ }
+
+ @Test
+ public void testAuthenticate_happyPathWithoutConfirmation() throws Exception {
+ setupAuthForOnly(BiometricAuthenticator.TYPE_FINGERPRINT);
+ mBiometricService = new BiometricService(mContext, new MockInjector());
+ mBiometricService.onStart();
+
+ // Start testing the happy path
+ invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */);
+ waitForIdle();
+
+ // Creates a pending auth session with the correct initial states
+ assertEquals(mBiometricService.mPendingAuthSession.mState,
+ BiometricService.STATE_AUTH_CALLED);
+
+ // Invokes <Modality>Service#prepareForAuthentication
+ ArgumentCaptor<Integer> cookieCaptor = ArgumentCaptor.forClass(Integer.class);
+ verify(mReceiver1, never()).onError(anyInt(), any(String.class));
+ verify(mBiometricService.mFingerprintService).prepareForAuthentication(
+ any(IBinder.class),
+ anyLong() /* sessionId */,
+ anyInt() /* userId */,
+ any(IBiometricServiceReceiverInternal.class),
+ anyString() /* opPackageName */,
+ cookieCaptor.capture() /* cookie */,
+ anyInt() /* callingUid */,
+ anyInt() /* callingPid */,
+ anyInt() /* callingUserId */);
+
+ // onReadyForAuthentication, mCurrentAuthSession state OK
+ mBiometricService.mImpl.onReadyForAuthentication(cookieCaptor.getValue(),
+ anyBoolean() /* requireConfirmation */, anyInt() /* userId */);
+ waitForIdle();
+ assertNull(mBiometricService.mPendingAuthSession);
+ assertEquals(mBiometricService.mCurrentAuthSession.mState,
+ BiometricService.STATE_AUTH_STARTED);
+
+ // startPreparedClient invoked
+ verify(mBiometricService.mFingerprintService)
+ .startPreparedClient(cookieCaptor.getValue());
+
+ // StatusBar showBiometricDialog invoked
+ verify(mBiometricService.mStatusBarService).showBiometricDialog(
+ eq(mBiometricService.mCurrentAuthSession.mBundle),
+ any(IBiometricServiceReceiverInternal.class),
+ eq(BiometricAuthenticator.TYPE_FINGERPRINT),
+ anyBoolean() /* requireConfirmation */,
+ anyInt() /* userId */,
+ eq(TEST_PACKAGE_NAME));
+
+ // Hardware authenticated
+ mBiometricService.mInternalReceiver.onAuthenticationSucceeded(
+ false /* requireConfirmation */,
+ new byte[69] /* HAT */);
+ waitForIdle();
+ // Waiting for SystemUI to send dismissed callback
+ assertEquals(mBiometricService.mCurrentAuthSession.mState,
+ BiometricService.STATE_AUTHENTICATED_PENDING_SYSUI);
+ // Notify SystemUI hardware authenticated
+ verify(mBiometricService.mStatusBarService).onBiometricAuthenticated(
+ eq(true) /* authenticated */, eq(null) /* failureReason */);
+
+ // SystemUI sends callback with dismissed reason
+ mBiometricService.mInternalReceiver.onDialogDismissed(
+ BiometricPrompt.DISMISSED_REASON_CONFIRM_NOT_REQUIRED);
+ waitForIdle();
+ // HAT sent to keystore
+ verify(mBiometricService.mKeyStore).addAuthToken(any(byte[].class));
+ // Send onAuthenticated to client
+ verify(mReceiver1).onAuthenticationSucceeded();
+ // Current session becomes null
+ assertNull(mBiometricService.mCurrentAuthSession);
+ }
+
+ @Test
+ public void testAuthenticate_happyPathWithConfirmation() throws Exception {
+ setupAuthForOnly(BiometricAuthenticator.TYPE_FACE);
+ invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
+ true /* requireConfirmation */);
+
+ // Test authentication succeeded goes to PENDING_CONFIRMATION and that the HAT is not
+ // sent to KeyStore yet
+ mBiometricService.mInternalReceiver.onAuthenticationSucceeded(
+ true /* requireConfirmation */,
+ new byte[69] /* HAT */);
+ waitForIdle();
+ // Waiting for SystemUI to send confirmation callback
+ assertEquals(mBiometricService.mCurrentAuthSession.mState,
+ BiometricService.STATE_AUTH_PENDING_CONFIRM);
+ verify(mBiometricService.mKeyStore, never()).addAuthToken(any(byte[].class));
+
+ // SystemUI sends confirm, HAT is sent to keystore and client is notified.
+ mBiometricService.mInternalReceiver.onDialogDismissed(
+ BiometricPrompt.DISMISSED_REASON_CONFIRMED);
+ waitForIdle();
+ verify(mBiometricService.mKeyStore).addAuthToken(any(byte[].class));
+ verify(mReceiver1).onAuthenticationSucceeded();
+ }
+
+ @Test
+ public void testRejectFace_whenAuthenticating_notifiesSystemUIAndClient_thenPaused()
+ throws Exception {
+ setupAuthForOnly(BiometricAuthenticator.TYPE_FACE);
+ invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
+ false /* requireConfirmation */);
+
+ mBiometricService.mInternalReceiver.onAuthenticationFailed();
+ waitForIdle();
+
+ verify(mBiometricService.mStatusBarService)
+ .onBiometricAuthenticated(eq(false), eq(ERROR_NOT_RECOGNIZED));
+ verify(mReceiver1).onAuthenticationFailed();
+ assertEquals(mBiometricService.mCurrentAuthSession.mState,
+ BiometricService.STATE_AUTH_PAUSED);
+ }
+
+ @Test
+ public void testRejectFingerprint_whenAuthenticating_notifiesAndKeepsAuthenticating()
+ throws Exception {
+ setupAuthForOnly(BiometricAuthenticator.TYPE_FINGERPRINT);
+ invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
+ false /* requireConfirmation */);
+
+ mBiometricService.mInternalReceiver.onAuthenticationFailed();
+ waitForIdle();
+
+ verify(mBiometricService.mStatusBarService)
+ .onBiometricAuthenticated(eq(false), eq(ERROR_NOT_RECOGNIZED));
+ verify(mReceiver1).onAuthenticationFailed();
+ assertEquals(mBiometricService.mCurrentAuthSession.mState,
+ BiometricService.STATE_AUTH_STARTED);
+ }
+
+ @Test
+ public void testErrorCanceled_whenAuthenticating_notifiesSystemUIAndClient() throws Exception {
+ setupAuthForOnly(BiometricAuthenticator.TYPE_FINGERPRINT);
+ invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
+ false /* requireConfirmation */);
+
+ // Create a new pending auth session but don't start it yet. HAL contract is that previous
+ // one must get ERROR_CANCELED. Simulate that here by creating the pending auth session,
+ // sending ERROR_CANCELED to the current auth session, and then having the second one
+ // onReadyForAuthentication.
+ invokeAuthenticate(mBiometricService.mImpl, mReceiver2, false /* requireConfirmation */);
+ waitForIdle();
+
+ assertEquals(mBiometricService.mCurrentAuthSession.mState,
+ BiometricService.STATE_AUTH_STARTED);
+ mBiometricService.mInternalReceiver.onError(
+ getCookieForCurrentSession(mBiometricService.mCurrentAuthSession),
+ BiometricConstants.BIOMETRIC_ERROR_CANCELED, ERROR_CANCELED);
+ waitForIdle();
+
+ // Auth session doesn't become null until SystemUI responds that the animation is completed
+ assertNotNull(mBiometricService.mCurrentAuthSession);
+ // ERROR_CANCELED is not sent until SystemUI responded that animation is completed
+ verify(mReceiver1, never()).onError(
+ anyInt(), anyString());
+ verify(mReceiver2, never()).onError(anyInt(), any(String.class));
+
+ // SystemUI dialog closed
+ verify(mBiometricService.mStatusBarService).hideBiometricDialog();
+
+ // After SystemUI notifies that the animation has completed
+ mBiometricService.mInternalReceiver
+ .onDialogDismissed(BiometricPrompt.DISMISSED_REASON_SERVER_REQUESTED);
+ waitForIdle();
+ verify(mReceiver1).onError(
+ eq(BiometricConstants.BIOMETRIC_ERROR_CANCELED),
+ eq(ERROR_CANCELED));
+ assertNull(mBiometricService.mCurrentAuthSession);
+ }
+
+ @Test
+ public void testErrorHalTimeout_whenAuthenticating_entersPausedState() throws Exception {
+ setupAuthForOnly(BiometricAuthenticator.TYPE_FACE);
+ invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
+ false /* requireConfirmation */);
+
+ mBiometricService.mInternalReceiver.onError(
+ getCookieForCurrentSession(mBiometricService.mCurrentAuthSession),
+ BiometricConstants.BIOMETRIC_ERROR_TIMEOUT,
+ ERROR_TIMEOUT);
+ waitForIdle();
+
+ assertEquals(mBiometricService.mCurrentAuthSession.mState,
+ BiometricService.STATE_AUTH_PAUSED);
+ verify(mBiometricService.mStatusBarService)
+ .onBiometricAuthenticated(eq(false), eq(ERROR_TIMEOUT));
+ // Timeout does not count as fail as per BiometricPrompt documentation.
+ verify(mReceiver1, never()).onAuthenticationFailed();
+
+ // No pending auth session. Pressing try again will create one.
+ assertNull(mBiometricService.mPendingAuthSession);
+
+ // Pressing "Try again" on SystemUI starts a new auth session.
+ mBiometricService.mInternalReceiver.onTryAgainPressed();
+ waitForIdle();
+
+ // The last one is still paused, and a new one has been created.
+ assertEquals(mBiometricService.mCurrentAuthSession.mState,
+ BiometricService.STATE_AUTH_PAUSED);
+ assertEquals(mBiometricService.mPendingAuthSession.mState,
+ BiometricService.STATE_AUTH_CALLED);
+
+ // Test resuming when hardware becomes ready. SystemUI should not be requested to
+ // show another dialog since it's already showing.
+ resetStatusBar();
+ startPendingAuthSession(mBiometricService);
+ waitForIdle();
+ verify(mBiometricService.mStatusBarService, never()).showBiometricDialog(
+ any(Bundle.class),
+ any(IBiometricServiceReceiverInternal.class),
+ anyInt(),
+ anyBoolean() /* requireConfirmation */,
+ anyInt() /* userId */,
+ anyString());
+ }
+
+ @Test
+ public void testErrorFromHal_whenPaused_notifiesSystemUIAndClient() throws Exception {
+ setupAuthForOnly(BiometricAuthenticator.TYPE_FACE);
+ invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
+ false /* requireCOnfirmation */);
+
+ mBiometricService.mInternalReceiver.onError(
+ getCookieForCurrentSession(mBiometricService.mCurrentAuthSession),
+ BiometricConstants.BIOMETRIC_ERROR_TIMEOUT,
+ ERROR_TIMEOUT);
+ mBiometricService.mInternalReceiver.onError(
+ getCookieForCurrentSession(mBiometricService.mCurrentAuthSession),
+ BiometricConstants.BIOMETRIC_ERROR_CANCELED,
+ ERROR_CANCELED);
+ waitForIdle();
+
+ // Client receives error immediately
+ verify(mReceiver1).onError(
+ eq(BiometricConstants.BIOMETRIC_ERROR_CANCELED),
+ eq(ERROR_CANCELED));
+ // Dialog is hidden immediately
+ verify(mBiometricService.mStatusBarService).hideBiometricDialog();
+ // Auth session is over
+ assertNull(mBiometricService.mCurrentAuthSession);
+ }
+
+ @Test
+ public void testErrorFromHal_whileAuthenticating_waitsForSysUIBeforeNotifyingClient()
+ throws Exception {
+ // For errors that show in SystemUI, BiometricService stays in STATE_ERROR_PENDING_SYSUI
+ // until SystemUI notifies us that the dialog is dismissed at which point the current
+ // session is done.
+ setupAuthForOnly(BiometricAuthenticator.TYPE_FINGERPRINT);
+ invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
+ false /* requireConfirmation */);
+
+ mBiometricService.mInternalReceiver.onError(
+ getCookieForCurrentSession(mBiometricService.mCurrentAuthSession),
+ BiometricConstants.BIOMETRIC_ERROR_UNABLE_TO_PROCESS,
+ ERROR_UNABLE_TO_PROCESS);
+ waitForIdle();
+
+ // Sends error to SystemUI and does not notify client yet
+ assertEquals(mBiometricService.mCurrentAuthSession.mState,
+ BiometricService.STATE_ERROR_PENDING_SYSUI);
+ verify(mBiometricService.mStatusBarService)
+ .onBiometricError(eq(ERROR_UNABLE_TO_PROCESS));
+ verify(mBiometricService.mStatusBarService, never()).hideBiometricDialog();
+ verify(mReceiver1, never()).onError(anyInt(), anyString());
+
+ // SystemUI animation completed, client is notified, auth session is over
+ mBiometricService.mInternalReceiver
+ .onDialogDismissed(BiometricPrompt.DISMISSED_REASON_ERROR);
+ waitForIdle();
+ verify(mReceiver1).onError(
+ eq(BiometricConstants.BIOMETRIC_ERROR_UNABLE_TO_PROCESS),
+ eq(ERROR_UNABLE_TO_PROCESS));
+ assertNull(mBiometricService.mCurrentAuthSession);
+ }
+
+ @Test
+ public void testDismissedReasonUserCancel_whileAuthenticating_cancelsHalAuthentication()
+ throws Exception {
+ setupAuthForOnly(BiometricAuthenticator.TYPE_FINGERPRINT);
+ invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
+ false /* requireConfirmation */);
+
+ mBiometricService.mInternalReceiver
+ .onDialogDismissed(BiometricPrompt.DISMISSED_REASON_USER_CANCEL);
+ waitForIdle();
+ verify(mReceiver1).onError(
+ eq(BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED),
+ eq(ERROR_USER_CANCELED));
+ verify(mBiometricService.mFingerprintService).cancelAuthenticationFromService(
+ any(),
+ any(),
+ anyInt(),
+ anyInt(),
+ anyInt(),
+ eq(false) /* fromClient */);
+ assertNull(mBiometricService.mCurrentAuthSession);
+ }
+
+ @Test
+ public void testDismissedReasonNegative_whilePaused_doesntInvokeHalCancel() throws Exception {
+ setupAuthForOnly(BiometricAuthenticator.TYPE_FACE);
+ invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
+ false /* requireConfirmation */);
+
+ mBiometricService.mInternalReceiver.onError(
+ getCookieForCurrentSession(mBiometricService.mCurrentAuthSession),
+ BiometricConstants.BIOMETRIC_ERROR_TIMEOUT,
+ ERROR_TIMEOUT);
+ mBiometricService.mInternalReceiver.onDialogDismissed(
+ BiometricPrompt.DISMISSED_REASON_NEGATIVE);
+ waitForIdle();
+
+ verify(mBiometricService.mFaceService, never()).cancelAuthenticationFromService(
+ any(),
+ any(),
+ anyInt(),
+ anyInt(),
+ anyInt(),
+ anyBoolean());
+ }
+
+ @Test
+ public void testDismissedReasonUserCancel_whilePaused_doesntInvokeHalCancel() throws Exception {
+ setupAuthForOnly(BiometricAuthenticator.TYPE_FACE);
+ invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
+ false /* requireConfirmation */);
+
+ mBiometricService.mInternalReceiver.onError(
+ getCookieForCurrentSession(mBiometricService.mCurrentAuthSession),
+ BiometricConstants.BIOMETRIC_ERROR_TIMEOUT,
+ ERROR_TIMEOUT);
+ mBiometricService.mInternalReceiver.onDialogDismissed(
+ BiometricPrompt.DISMISSED_REASON_USER_CANCEL);
+ waitForIdle();
+
+ verify(mBiometricService.mFaceService, never()).cancelAuthenticationFromService(
+ any(),
+ any(),
+ anyInt(),
+ anyInt(),
+ anyInt(),
+ anyBoolean());
+ }
+
+ @Test
+ public void testDismissedReasonUserCancel_whenPendingConfirmation() throws Exception {
+ setupAuthForOnly(BiometricAuthenticator.TYPE_FACE);
+ invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
+ true /* requireConfirmation */);
+
+ mBiometricService.mInternalReceiver.onAuthenticationSucceeded(
+ true /* requireConfirmation */,
+ new byte[69] /* HAT */);
+ mBiometricService.mInternalReceiver.onDialogDismissed(
+ BiometricPrompt.DISMISSED_REASON_USER_CANCEL);
+ waitForIdle();
+
+ // doesn't send cancel to HAL
+ verify(mBiometricService.mFaceService, never()).cancelAuthenticationFromService(
+ any(),
+ any(),
+ anyInt(),
+ anyInt(),
+ anyInt(),
+ anyBoolean());
+ verify(mReceiver1).onError(
+ eq(BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED),
+ eq(ERROR_USER_CANCELED));
+ assertNull(mBiometricService.mCurrentAuthSession);
+ }
+
+ @Test
+ public void testAcquire_whenAuthenticating_sentToSystemUI() throws Exception {
+ setupAuthForOnly(BiometricAuthenticator.TYPE_FINGERPRINT);
+ invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
+ false /* requireConfirmation */);
+
+ mBiometricService.mInternalReceiver.onAcquired(
+ FingerprintManager.FINGERPRINT_ACQUIRED_IMAGER_DIRTY,
+ FINGERPRINT_ACQUIRED_SENSOR_DIRTY);
+ waitForIdle();
+
+ // Sends to SysUI and stays in authenticating state
+ verify(mBiometricService.mStatusBarService)
+ .onBiometricHelp(eq(FINGERPRINT_ACQUIRED_SENSOR_DIRTY));
+ assertEquals(mBiometricService.mCurrentAuthSession.mState,
+ BiometricService.STATE_AUTH_STARTED);
+ }
+
+ // Helper methods
+
+ private void setupAuthForOnly(int modality) {
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT))
+ .thenReturn(false);
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(false);
+
+ if (modality == BiometricAuthenticator.TYPE_FINGERPRINT) {
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT))
+ .thenReturn(true);
+ when(mFingerprintManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
+ when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+ } else if (modality == BiometricAuthenticator.TYPE_FACE) {
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(true);
+ when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
+ when(mFaceManager.isHardwareDetected()).thenReturn(true);
+ } else {
+ fail("Unknown modality: " + modality);
+ }
+
+ mBiometricService = new BiometricService(mContext, new MockInjector());
+ mBiometricService.onStart();
+
+ when(mBiometricService.mSettingObserver.getFaceEnabledForApps(anyInt())).thenReturn(true);
+ }
+
+ private void resetReceiver() {
+ mReceiver1 = mock(IBiometricServiceReceiver.class);
+ mReceiver2 = mock(IBiometricServiceReceiver.class);
+ }
+
+ private void resetStatusBar() {
+ mBiometricService.mStatusBarService = mock(IStatusBarService.class);
+ }
+
+ private void invokeAuthenticateAndStart(IBiometricService.Stub service,
+ IBiometricServiceReceiver receiver, boolean requireConfirmation) throws Exception {
+ // Request auth, creates a pending session
+ invokeAuthenticate(service, receiver, requireConfirmation);
+ waitForIdle();
+
+ startPendingAuthSession(mBiometricService);
+ waitForIdle();
+ }
+
+ private static void startPendingAuthSession(BiometricService service) throws Exception {
+ // Get the cookie so we can pretend the hardware is ready to authenticate
+ // Currently we only support single modality per auth
+ assertEquals(service.mPendingAuthSession.mModalitiesWaiting.values().size(), 1);
+ final int cookie = service.mPendingAuthSession.mModalitiesWaiting.values()
+ .iterator().next();
+ assertNotEquals(cookie, 0);
+
+ service.mImpl.onReadyForAuthentication(cookie,
+ anyBoolean() /* requireConfirmation */, anyInt() /* userId */);
+ }
+
+ private static void invokeAuthenticate(IBiometricService.Stub service,
+ IBiometricServiceReceiver receiver, boolean requireConfirmation) throws Exception {
+ service.authenticate(
+ new Binder() /* token */,
+ 0 /* sessionId */,
+ 0 /* userId */,
+ receiver,
+ TEST_PACKAGE_NAME /* packageName */,
+ createTestBiometricPromptBundle(requireConfirmation),
+ null /* IBiometricConfirmDeviceCredentialCallback */);
+ }
+
+ private static Bundle createTestBiometricPromptBundle(boolean requireConfirmation) {
+ final Bundle bundle = new Bundle();
+ bundle.putBoolean(BiometricPrompt.KEY_REQUIRE_CONFIRMATION, requireConfirmation);
+ return bundle;
+ }
+
+ private static int getCookieForCurrentSession(BiometricService.AuthSession session) {
+ assertEquals(session.mModalitiesMatched.values().size(), 1);
+ return session.mModalitiesMatched.values().iterator().next();
+ }
+
+ private static void waitForIdle() {
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index 09ae3a2..ba12b73 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -139,7 +139,7 @@
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.util.test.BroadcastInterceptingContext;
import com.android.internal.util.test.BroadcastInterceptingContext.FutureIntent;
-import com.android.server.DeviceIdleController;
+import com.android.server.DeviceIdleInternal;
import com.android.server.LocalServices;
import com.google.common.util.concurrent.AbstractFuture;
@@ -293,7 +293,7 @@
};
private void registerLocalServices() {
- addLocalServiceMock(DeviceIdleController.LocalService.class);
+ addLocalServiceMock(DeviceIdleInternal.class);
final UsageStatsManagerInternal usageStats =
addLocalServiceMock(UsageStatsManagerInternal.class);
@@ -442,7 +442,7 @@
// Added in registerLocalServices()
LocalServices.removeServiceForTest(ActivityManagerInternal.class);
LocalServices.removeServiceForTest(PowerManagerInternal.class);
- LocalServices.removeServiceForTest(DeviceIdleController.LocalService.class);
+ LocalServices.removeServiceForTest(DeviceIdleInternal.class);
LocalServices.removeServiceForTest(UsageStatsManagerInternal.class);
LocalServices.removeServiceForTest(NetworkStatsManagerInternal.class);
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
index 75e5847..819091c 100644
--- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
@@ -19,12 +19,12 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.app.AppOpsManager;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
@@ -54,10 +54,7 @@
IPermissionManager mPermissionManagerMock;
@Mock
- AppsFilter.ConfigProvider mConfigProviderMock;
-
- @Mock
- AppOpsManager mAppOpsManager;
+ AppsFilter.FeatureConfig mFeatureConfigMock;
private Map<String, PackageParser.Package> mExisting = new ArrayMap<>();
@@ -108,16 +105,23 @@
when(mPermissionManagerMock
.checkPermission(anyString(), anyString(), anyInt()))
.thenReturn(PackageManager.PERMISSION_DENIED);
- when(mConfigProviderMock.isEnabled()).thenReturn(true);
- when(mAppOpsManager.checkOpNoThrow(eq(AppOpsManager.OP_QUERY_ALL_PACKAGES), eq(
- DUMMY_CALLING_UID), anyString())).thenReturn(AppOpsManager.MODE_DEFAULT);
+ when(mFeatureConfigMock.isGloballyEnabled()).thenReturn(true);
+ when(mFeatureConfigMock.packageIsEnabled(any(PackageParser.Package.class)))
+ .thenReturn(true);
+ }
+
+ @Test
+ public void testSystemReadyPropogates() throws Exception {
+ final AppsFilter appsFilter =
+ new AppsFilter(mFeatureConfigMock, mPermissionManagerMock, new String[]{}, false);
+ appsFilter.onSystemReady();
+ verify(mFeatureConfigMock).onSystemReady();
}
@Test
public void testQueriesAction_FilterMatches() {
final AppsFilter appsFilter =
- new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
- new String[]{}, false);
+ new AppsFilter(mFeatureConfigMock, mPermissionManagerMock, new String[]{}, false);
PackageSetting target = simulateAddPackage(appsFilter,
pkg("com.some.package", new IntentFilter("TEST_ACTION"))).build();
@@ -130,8 +134,7 @@
@Test
public void testQueriesAction_NoMatchingAction_Filters() {
final AppsFilter appsFilter =
- new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
- new String[]{}, false);
+ new AppsFilter(mFeatureConfigMock, mPermissionManagerMock, new String[]{}, false);
PackageSetting target = simulateAddPackage(appsFilter,
pkg("com.some.package")).build();
@@ -144,7 +147,7 @@
@Test
public void testQueriesAction_NoMatchingActionFilterLowSdk_DoesntFilter() {
final AppsFilter appsFilter =
- new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
+ new AppsFilter(mFeatureConfigMock, mPermissionManagerMock,
new String[]{}, false);
PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package")).build();
@@ -158,7 +161,7 @@
@Test
public void testNoQueries_Filters() {
final AppsFilter appsFilter =
- new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
+ new AppsFilter(mFeatureConfigMock, mPermissionManagerMock,
new String[]{}, false);
PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package")).build();
@@ -171,7 +174,7 @@
@Test
public void testForceQueryable_DoesntFilter() {
final AppsFilter appsFilter =
- new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
+ new AppsFilter(mFeatureConfigMock, mPermissionManagerMock,
new String[]{}, false);
PackageSetting target =
@@ -186,7 +189,7 @@
@Test
public void testForceQueryableByDevice_SystemCaller_DoesntFilter() {
final AppsFilter appsFilter =
- new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
+ new AppsFilter(mFeatureConfigMock, mPermissionManagerMock,
new String[]{"com.some.package"}, false);
PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"))
@@ -201,7 +204,7 @@
@Test
public void testForceQueryableByDevice_NonSystemCaller_Filters() {
final AppsFilter appsFilter =
- new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
+ new AppsFilter(mFeatureConfigMock, mPermissionManagerMock,
new String[]{"com.some.package"}, false);
PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package")).build();
@@ -215,7 +218,7 @@
@Test
public void testSystemQueryable_DoesntFilter() {
final AppsFilter appsFilter =
- new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
+ new AppsFilter(mFeatureConfigMock, mPermissionManagerMock,
new String[]{}, true /* system force queryable */);
PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"))
@@ -230,7 +233,7 @@
@Test
public void testQueriesPackage_DoesntFilter() {
final AppsFilter appsFilter =
- new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
+ new AppsFilter(mFeatureConfigMock, mPermissionManagerMock,
new String[]{}, false);
PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package")).build();
@@ -241,55 +244,11 @@
}
@Test
- public void testNoQueries_AppOpModeDeny_Filters() {
- when(mAppOpsManager.checkOpNoThrow(eq(AppOpsManager.OP_QUERY_ALL_PACKAGES), eq(
- DUMMY_CALLING_UID), anyString())).thenReturn(AppOpsManager.MODE_ERRORED);
- final AppsFilter appsFilter =
- new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
- new String[]{}, false);
-
- PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package")).build();
- PackageSetting calling = simulateAddPackage(appsFilter,
- pkg("com.some.other.package")).build();
-
- assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
- }
-
- @Test
- public void testNoQueries_AppOpModeAllow_DoesntFilter() {
- when(mAppOpsManager.checkOpNoThrow(eq(AppOpsManager.OP_QUERY_ALL_PACKAGES), eq(
- DUMMY_CALLING_UID), anyString())).thenReturn(AppOpsManager.MODE_ALLOWED);
- final AppsFilter appsFilter =
- new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
- new String[]{}, false);
-
- PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package")).build();
- PackageSetting calling = simulateAddPackage(appsFilter,
- pkg("com.some.other.package")).build();
-
- assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
- }
-
- @Test
- public void testNoQueries_AppOpModeIgnore_Filters() {
- when(mAppOpsManager.checkOpNoThrow(eq(AppOpsManager.OP_QUERY_ALL_PACKAGES), eq(
- DUMMY_CALLING_UID), anyString())).thenReturn(AppOpsManager.MODE_IGNORED);
- final AppsFilter appsFilter =
- new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
- new String[]{}, false);
-
- PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package")).build();
- PackageSetting calling = simulateAddPackage(appsFilter,
- pkg("com.some.other.package")).build();
-
- assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
- }
-
- @Test
public void testNoQueries_FeatureOff_DoesntFilter() {
- when(mConfigProviderMock.isEnabled()).thenReturn(false);
+ when(mFeatureConfigMock.packageIsEnabled(any(PackageParser.Package.class)))
+ .thenReturn(false);
final AppsFilter appsFilter =
- new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
+ new AppsFilter(mFeatureConfigMock, mPermissionManagerMock,
new String[]{}, false);
PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package")).build();
@@ -302,7 +261,7 @@
@Test
public void testSystemUid_DoesntFilter() {
final AppsFilter appsFilter =
- new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
+ new AppsFilter(mFeatureConfigMock, mPermissionManagerMock,
new String[]{}, false);
PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package")).build();
@@ -315,7 +274,7 @@
@Test
public void testNonSystemUid_NoCallingSetting_Filters() {
final AppsFilter appsFilter =
- new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
+ new AppsFilter(mFeatureConfigMock, mPermissionManagerMock,
new String[]{}, false);
PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package")).build();
@@ -326,7 +285,7 @@
@Test
public void testNoTargetPackage_filters() {
final AppsFilter appsFilter =
- new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
+ new AppsFilter(mFeatureConfigMock, mPermissionManagerMock,
new String[]{}, false);
PackageSetting target = new PackageSettingBuilder()
diff --git a/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java b/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java
index 7986055..8cb5197 100644
--- a/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java
@@ -16,6 +16,7 @@
package com.android.server.rollback;
+import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
@@ -58,8 +59,8 @@
// All users are unlocked so we should snapshot data for them.
doReturn(true).when(helper).isUserCredentialLocked(eq(10));
doReturn(true).when(helper).isUserCredentialLocked(eq(11));
- PackageRollbackInfo info = createPackageRollbackInfo("com.foo.bar", new int[]{10, 11});
- helper.snapshotAppData(5, info);
+ PackageRollbackInfo info = createPackageRollbackInfo("com.foo.bar");
+ helper.snapshotAppData(5, info, new int[]{10, 11});
assertEquals(2, info.getPendingBackups().size());
assertEquals(10, info.getPendingBackups().get(0));
@@ -79,8 +80,8 @@
doReturn(true).when(helper).isUserCredentialLocked(eq(11));
when(installer.snapshotAppData(anyString(), anyInt(), anyInt(), anyInt())).thenReturn(239L);
- PackageRollbackInfo info2 = createPackageRollbackInfo("com.foo.bar", new int[]{10, 11});
- helper.snapshotAppData(7, info2);
+ PackageRollbackInfo info2 = createPackageRollbackInfo("com.foo.bar");
+ helper.snapshotAppData(7, info2, new int[]{10, 11});
assertEquals(1, info2.getPendingBackups().size());
assertEquals(11, info2.getPendingBackups().get(0));
@@ -234,22 +235,22 @@
wasRecentlyRestored.getPendingRestores().add(
new RestoreInfo(73 /* userId */, 239 /* appId*/, "seInfo"));
- RollbackData dataWithPendingBackup = new RollbackData(101, new File("/does/not/exist"), -1);
+ Rollback dataWithPendingBackup = new Rollback(101, new File("/does/not/exist"), -1);
dataWithPendingBackup.info.getPackages().add(pendingBackup);
- RollbackData dataWithRecentRestore = new RollbackData(17239, new File("/does/not/exist"),
+ Rollback dataWithRecentRestore = new Rollback(17239, new File("/does/not/exist"),
-1);
dataWithRecentRestore.info.getPackages().add(wasRecentlyRestored);
- RollbackData dataForDifferentUser = new RollbackData(17239, new File("/does/not/exist"),
+ Rollback dataForDifferentUser = new Rollback(17239, new File("/does/not/exist"),
-1);
dataForDifferentUser.info.getPackages().add(ignoredInfo);
- RollbackData dataForRestore = new RollbackData(17239, new File("/does/not/exist"), -1);
+ Rollback dataForRestore = new Rollback(17239, new File("/does/not/exist"), -1);
dataForRestore.info.getPackages().add(pendingRestore);
dataForRestore.info.getPackages().add(wasRecentlyRestored);
- Set<RollbackData> changed = helper.commitPendingBackupAndRestoreForUser(37,
+ Set<Rollback> changed = helper.commitPendingBackupAndRestoreForUser(37,
Arrays.asList(dataWithPendingBackup, dataWithRecentRestore, dataForDifferentUser,
dataForRestore));
InOrder inOrder = Mockito.inOrder(installer);
@@ -264,7 +265,7 @@
assertEquals(-1, pendingBackup.getPendingBackups().indexOf(37));
assertEquals(53, pendingBackup.getCeSnapshotInodes().get(37));
- // Check that changed returns correct RollbackData.
+ // Check that changed returns correct Rollback.
assertEquals(3, changed.size());
assertTrue(changed.contains(dataWithPendingBackup));
assertTrue(changed.contains(dataWithRecentRestore));
@@ -278,4 +279,15 @@
inOrder.verifyNoMoreInteractions();
}
+
+ @Test
+ public void snapshotAddDataSavesSnapshottedUsersToInfo() {
+ Installer installer = mock(Installer.class);
+ AppDataRollbackHelper helper = new AppDataRollbackHelper(installer);
+
+ PackageRollbackInfo info = createPackageRollbackInfo("com.foo.bar");
+ helper.snapshotAppData(5, info, new int[]{10, 11});
+
+ assertArrayEquals(info.getSnapshottedUsers().toArray(), new int[]{10, 11});
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index c1c0a30..57caa1d 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -2766,6 +2766,18 @@
}
@Test
+ public void testReadPolicyXml_readSnoozedNotificationsFromXml() throws Exception {
+ final String upgradeXml = "<notification-policy version=\"1\">"
+ + "<snoozed-notifications>></snoozed-notifications>"
+ + "</notification-policy>";
+ mService.readPolicyXml(
+ new BufferedInputStream(new ByteArrayInputStream(upgradeXml.getBytes())),
+ false,
+ UserHandle.USER_ALL);
+ verify(mSnoozeHelper, times(1)).readXml(any(XmlPullParser.class));
+ }
+
+ @Test
public void testReadPolicyXml_readApprovedServicesFromSettings() throws Exception {
final String preupgradeXml = "<notification-policy version=\"1\">"
+ "<ranking></ranking>"
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
index 2e7277f..36175a9 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
@@ -18,6 +18,7 @@
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.assertNull;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
@@ -37,9 +38,11 @@
import android.service.notification.StatusBarNotification;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.IntArray;
+import android.util.Xml;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.util.FastXmlSerializer;
import com.android.server.UiServiceTestCase;
import org.junit.Before;
@@ -48,6 +51,15 @@
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -69,6 +81,117 @@
}
@Test
+ public void testWriteXMLformattedCorrectly_testReadingCorrectTime()
+ throws XmlPullParserException, IOException {
+ final String max_time_str = Long.toString(Long.MAX_VALUE);
+ final String xml_string = "<snoozed-notifications>"
+ + "<notification version=\"1\" user-id=\"0\" notification=\"notification\" "
+ + "pkg=\"pkg\" key=\"key\" time=\"" + max_time_str + "\"/>"
+ + "<notification version=\"1\" user-id=\"0\" notification=\"notification\" "
+ + "pkg=\"pkg\" key=\"key2\" time=\"" + max_time_str + "\"/>"
+ + "</snoozed-notifications>";
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(new BufferedInputStream(
+ new ByteArrayInputStream(xml_string.getBytes())), null);
+ mSnoozeHelper.readXml(parser);
+ assertTrue("Should read the notification time from xml and it should be more than zero",
+ 0 < mSnoozeHelper.getSnoozeTimeForUnpostedNotification(
+ 0, "pkg", "key").doubleValue());
+ }
+
+ @Test
+ public void testWriteXMLformattedCorrectly_testCorrectContextURI()
+ throws XmlPullParserException, IOException {
+ final String max_time_str = Long.toString(Long.MAX_VALUE);
+ final String xml_string = "<snoozed-notifications>"
+ + "<context version=\"1\" user-id=\"0\" notification=\"notification\" "
+ + "pkg=\"pkg\" key=\"key\" id=\"uri\"/>"
+ + "<context version=\"1\" user-id=\"0\" notification=\"notification\" "
+ + "pkg=\"pkg\" key=\"key2\" id=\"uri\"/>"
+ + "</snoozed-notifications>";
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(new BufferedInputStream(
+ new ByteArrayInputStream(xml_string.getBytes())), null);
+ mSnoozeHelper.readXml(parser);
+ assertEquals("Should read the notification context from xml and it should be `uri",
+ "uri", mSnoozeHelper.getSnoozeContextForUnpostedNotification(
+ 0, "pkg", "key"));
+ }
+
+ @Test
+ public void testReadValidSnoozedFromCorrectly_timeDeadline()
+ throws XmlPullParserException, IOException {
+ NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
+ mSnoozeHelper.snooze(r, 999999999);
+ XmlSerializer serializer = new FastXmlSerializer();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
+ serializer.startDocument(null, true);
+ mSnoozeHelper.writeXml(serializer);
+ serializer.endDocument();
+ serializer.flush();
+
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(new BufferedInputStream(
+ new ByteArrayInputStream(baos.toByteArray())), "utf-8");
+ mSnoozeHelper.readXml(parser);
+ assertTrue("Should read the notification time from xml and it should be more than zero",
+ 0 < mSnoozeHelper.getSnoozeTimeForUnpostedNotification(
+ 0, "pkg", r.getKey()).doubleValue());
+ }
+
+
+ @Test
+ public void testReadExpiredSnoozedNotification() throws
+ XmlPullParserException, IOException, InterruptedException {
+ NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
+ mSnoozeHelper.snooze(r, 0);
+ // Thread.sleep(100);
+ XmlSerializer serializer = new FastXmlSerializer();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
+ serializer.startDocument(null, true);
+ mSnoozeHelper.writeXml(serializer);
+ serializer.endDocument();
+ serializer.flush();
+ Thread.sleep(10);
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(new BufferedInputStream(
+ new ByteArrayInputStream(baos.toByteArray())), "utf-8");
+ mSnoozeHelper.readXml(parser);
+ int systemUser = UserHandle.SYSTEM.getIdentifier();
+ assertTrue("Should see a past time returned",
+ System.currentTimeMillis() > mSnoozeHelper.getSnoozeTimeForUnpostedNotification(
+ systemUser, "pkg", r.getKey()).longValue());
+ }
+
+ @Test
+ public void testCleanupContextShouldRemovePersistedRecord() {
+ NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
+ mSnoozeHelper.snooze(r, "context");
+ mSnoozeHelper.cleanupPersistedContext(r.sbn.getKey());
+ assertNull(mSnoozeHelper.getSnoozeContextForUnpostedNotification(
+ r.getUser().getIdentifier(),
+ r.sbn.getPackageName(),
+ r.sbn.getKey()
+ ));
+ }
+
+ @Test
+ public void testReadNoneSnoozedNotification() throws XmlPullParserException,
+ IOException, InterruptedException {
+ NotificationRecord r = getNotificationRecord(
+ "pkg", 1, "one", UserHandle.SYSTEM);
+ mSnoozeHelper.snooze(r, 0);
+
+ assertEquals("should see a zero value for unsnoozed notification",
+ 0L,
+ mSnoozeHelper.getSnoozeTimeForUnpostedNotification(
+ UserHandle.SYSTEM.getIdentifier(),
+ "not_my_package", r.getKey()).longValue());
+ }
+
+ @Test
public void testSnoozeForTime() throws Exception {
NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
mSnoozeHelper.snooze(r, 1000);
@@ -84,7 +207,7 @@
@Test
public void testSnooze() throws Exception {
NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
- mSnoozeHelper.snooze(r);
+ mSnoozeHelper.snooze(r, (String) null);
verify(mAm, never()).setExactAndAllowWhileIdle(
anyInt(), anyLong(), any(PendingIntent.class));
assertTrue(mSnoozeHelper.isSnoozed(
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
index 63b9198..6c78f6f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
@@ -28,6 +28,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
@@ -140,7 +141,8 @@
public void testNotResumeHomeStackOnRemovingDisplay() {
// Create a display which supports system decoration and allows reparenting stacks to
// another display when the display is removed.
- final ActivityDisplay display = spy(createNewActivityDisplay());
+ final ActivityDisplay display = createNewActivityDisplay();
+ spyOn(display);
doReturn(false).when(display).shouldDestroyContentOnRemove();
doReturn(true).when(display).supportsSystemDecorations();
mRootActivityContainer.addChild(display, ActivityDisplay.POSITION_TOP);
@@ -304,14 +306,18 @@
ACTIVITY_TYPE_STANDARD, ON_TOP);
final ActivityStack stack4 = display.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, ON_TOP);
- final TaskRecord task1 = new TaskBuilder(mService.mStackSupervisor).setStack(
- stack1).setTaskId(1).build();
- final TaskRecord task2 = new TaskBuilder(mService.mStackSupervisor).setStack(
- stack2).setTaskId(2).build();
- final TaskRecord task3 = new TaskBuilder(mService.mStackSupervisor).setStack(
- stack3).setTaskId(3).build();
- final TaskRecord task4 = new TaskBuilder(mService.mStackSupervisor).setStack(
- stack4).setTaskId(4).build();
+ final TaskRecord task1 = new TaskBuilder(mService.mStackSupervisor)
+ .setStack(stack1)
+ .build();
+ final TaskRecord task2 = new TaskBuilder(mService.mStackSupervisor)
+ .setStack(stack2)
+ .build();
+ final TaskRecord task3 = new TaskBuilder(mService.mStackSupervisor)
+ .setStack(stack3)
+ .build();
+ final TaskRecord task4 = new TaskBuilder(mService.mStackSupervisor)
+ .setStack(stack4)
+ .build();
// Reordering stacks while removing stacks.
doAnswer(invocation -> {
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
index 23bae88..977dd8e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -61,13 +61,13 @@
private ActivityMetricsLaunchObserver mLaunchObserver;
private ActivityMetricsLaunchObserverRegistry mLaunchObserverRegistry;
- private TestActivityStack mStack;
+ private ActivityStack mStack;
private TaskRecord mTask;
private ActivityRecord mActivityRecord;
private ActivityRecord mActivityRecordTrampoline;
@Before
- public void setUpAMLO() throws Exception {
+ public void setUpAMLO() {
mLaunchObserver = mock(ActivityMetricsLaunchObserver.class);
// ActivityStackSupervisor always creates its own instance of ActivityMetricsLogger.
@@ -78,15 +78,19 @@
// Sometimes we need an ActivityRecord for ActivityMetricsLogger to do anything useful.
// This seems to be the easiest way to create an ActivityRecord.
- mStack = mRootActivityContainer.getDefaultDisplay().createStack(
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- mTask = new TaskBuilder(mSupervisor).setStack(mStack).build();
- mActivityRecord = new ActivityBuilder(mService).setTask(mTask).build();
+ mStack = new StackBuilder(mRootActivityContainer)
+ .setActivityType(ACTIVITY_TYPE_STANDARD)
+ .setWindowingMode(WINDOWING_MODE_FULLSCREEN)
+ .setOnTop(true)
+ .setCreateActivity(true)
+ .build();
+ mTask = mStack.topTask();
+ mActivityRecord = mTask.getTopActivity();
mActivityRecordTrampoline = new ActivityBuilder(mService).setTask(mTask).build();
}
@After
- public void tearDownAMLO() throws Exception {
+ public void tearDownAMLO() {
if (mLaunchObserverRegistry != null) { // Don't NPE if setUp failed.
mLaunchObserverRegistry.unregisterLaunchObserver(mLaunchObserver);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 7b252cb..0f04788 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -16,6 +16,12 @@
package com.android.server.wm;
+import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
+import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.os.Process.NOBODY_UID;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Surface.ROTATION_0;
@@ -29,6 +35,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
import static com.android.server.wm.ActivityRecord.FINISH_RESULT_CANCELLED;
@@ -71,6 +78,7 @@
import android.platform.test.annotations.Presubmit;
import android.util.MergedConfiguration;
import android.util.MutableBoolean;
+import android.view.DisplayInfo;
import android.view.IRemoteAnimationFinishedCallback;
import android.view.IRemoteAnimationRunner.Stub;
import android.view.RemoteAnimationAdapter;
@@ -79,7 +87,6 @@
import androidx.test.filters.MediumTest;
import com.android.internal.R;
-import com.android.server.wm.utils.WmDisplayCutout;
import org.junit.Before;
import org.junit.Test;
@@ -96,13 +103,13 @@
@MediumTest
@Presubmit
public class ActivityRecordTests extends ActivityTestsBase {
- private TestActivityStack mStack;
+ private ActivityStack mStack;
private TaskRecord mTask;
private ActivityRecord mActivity;
@Before
public void setUp() throws Exception {
- mStack = (TestActivityStack) new StackBuilder(mRootActivityContainer).build();
+ mStack = new StackBuilder(mRootActivityContainer).build();
mTask = mStack.getChildAt(0);
mActivity = mTask.getTopActivity();
@@ -113,13 +120,13 @@
@Test
public void testStackCleanupOnClearingTask() {
mActivity.setTask(null);
- assertEquals(mStack.onActivityRemovedFromStackInvocationCount(), 1);
+ verify(mStack, times(1)).onActivityRemovedFromStack(any());
}
@Test
public void testStackCleanupOnActivityRemoval() {
mTask.removeActivity(mActivity);
- assertEquals(mStack.onActivityRemovedFromStackInvocationCount(), 1);
+ verify(mStack, times(1)).onActivityRemovedFromStack(any());
}
@Test
@@ -134,7 +141,7 @@
final TaskRecord newTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack)
.build();
mActivity.reparent(newTask, 0, null /*reason*/);
- assertEquals(mStack.onActivityRemovedFromStackInvocationCount(), 0);
+ verify(mStack, times(0)).onActivityRemovedFromStack(any());
}
@Test
@@ -181,7 +188,7 @@
assertTrue(mActivity.isState(STARTED));
mStack.mTranslucentActivityWaiting = null;
- topActivity.changeWindowTranslucency(false);
+ topActivity.setOccludesParent(false);
mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped behind non-opaque");
mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
assertTrue(mActivity.isState(STARTED));
@@ -261,8 +268,8 @@
public void testNewParentConfigurationIncrementsSeq() {
final Configuration newConfig = new Configuration(
mTask.getRequestedOverrideConfiguration());
- newConfig.orientation = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT
- ? Configuration.ORIENTATION_LANDSCAPE : Configuration.ORIENTATION_PORTRAIT;
+ newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT
+ ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT;
final int prevSeq = mActivity.getMergedOverrideConfiguration().seq;
mTask.onRequestedOverrideConfigurationChanged(newConfig);
@@ -277,7 +284,7 @@
.getRequestedOverrideConfiguration();
final Configuration newConfig = new Configuration();
- newConfig.orientation = Configuration.ORIENTATION_PORTRAIT;
+ newConfig.orientation = ORIENTATION_PORTRAIT;
final int prevSeq = mActivity.getMergedOverrideConfiguration().seq;
mActivity.onRequestedOverrideConfigurationChanged(newConfig);
@@ -293,10 +300,11 @@
mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
mActivity.getConfiguration()));
- mActivity.info.configChanges &= ~ActivityInfo.CONFIG_ORIENTATION;
+ mActivity.info.configChanges &= ~CONFIG_ORIENTATION;
final Configuration newConfig = new Configuration(mTask.getConfiguration());
- newConfig.orientation = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT
- ? Configuration.ORIENTATION_LANDSCAPE : Configuration.ORIENTATION_PORTRAIT;
+ newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT
+ ? ORIENTATION_LANDSCAPE
+ : ORIENTATION_PORTRAIT;
mTask.onRequestedOverrideConfigurationChanged(newConfig);
mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE;
@@ -315,13 +323,14 @@
mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
mActivity.getConfiguration()));
- mActivity.info.configChanges &= ~ActivityInfo.CONFIG_ORIENTATION;
+ mActivity.info.configChanges &= ~CONFIG_ORIENTATION;
final Configuration newConfig = new Configuration(mTask.getConfiguration());
- newConfig.orientation = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT
- ? Configuration.ORIENTATION_LANDSCAPE : Configuration.ORIENTATION_PORTRAIT;
+ newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT
+ ? ORIENTATION_LANDSCAPE
+ : ORIENTATION_PORTRAIT;
mTask.onRequestedOverrideConfigurationChanged(newConfig);
- doReturn(true).when(mTask.getTask()).isDragResizing();
+ doReturn(true).when(mTask.mTask).isDragResizing();
mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE;
@@ -355,30 +364,39 @@
@Test
public void testSetRequestedOrientationUpdatesConfiguration() throws Exception {
+ mActivity = new ActivityBuilder(mService)
+ .setTask(mTask)
+ .setConfigChanges(CONFIG_ORIENTATION | CONFIG_SCREEN_LAYOUT)
+ .build();
mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
- mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
mActivity.getConfiguration()));
- mActivity.info.configChanges |= ActivityInfo.CONFIG_ORIENTATION;
final Configuration newConfig = new Configuration(mActivity.getConfiguration());
- newConfig.orientation = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT
- ? Configuration.ORIENTATION_LANDSCAPE
- : Configuration.ORIENTATION_PORTRAIT;
+ final int shortSide = Math.min(newConfig.screenWidthDp, newConfig.screenHeightDp);
+ final int longSide = Math.max(newConfig.screenWidthDp, newConfig.screenHeightDp);
+ if (newConfig.orientation == ORIENTATION_PORTRAIT) {
+ newConfig.orientation = ORIENTATION_LANDSCAPE;
+ newConfig.screenWidthDp = longSide;
+ newConfig.screenHeightDp = shortSide;
+ } else {
+ newConfig.orientation = ORIENTATION_PORTRAIT;
+ newConfig.screenWidthDp = shortSide;
+ newConfig.screenHeightDp = longSide;
+ }
// Mimic the behavior that display doesn't handle app's requested orientation.
- doAnswer(invocation -> {
- mTask.onConfigurationChanged(newConfig);
- return null;
- }).when(mActivity.mAppWindowToken).setOrientation(anyInt(), any(), any());
+ final DisplayContent dc = mTask.mTask.getDisplayContent();
+ doReturn(false).when(dc).onDescendantOrientationChanged(any(), any());
+ doReturn(false).when(dc).handlesOrientationChangeFromDescendant();
final int requestedOrientation;
switch (newConfig.orientation) {
- case Configuration.ORIENTATION_LANDSCAPE:
- requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+ case ORIENTATION_LANDSCAPE:
+ requestedOrientation = SCREEN_ORIENTATION_LANDSCAPE;
break;
- case Configuration.ORIENTATION_PORTRAIT:
+ case ORIENTATION_PORTRAIT:
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
break;
default:
@@ -421,24 +439,33 @@
@Test
public void testPushConfigurationWhenLaunchTaskBehind() throws Exception {
+ mActivity = new ActivityBuilder(mService)
+ .setTask(mTask)
+ .setLaunchTaskBehind(true)
+ .setConfigChanges(CONFIG_ORIENTATION)
+ .build();
mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
- final TestActivityStack stack = (TestActivityStack) new StackBuilder(mRootActivityContainer)
- .build();
+ final ActivityStack stack = new StackBuilder(mRootActivityContainer).build();
try {
- stack.setIsTranslucent(false);
+ doReturn(false).when(stack).isStackTranslucent(any());
assertFalse(mStack.shouldBeVisible(null /* starting */));
- mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
mActivity.getConfiguration()));
- mActivity.mLaunchTaskBehind = true;
- mActivity.info.configChanges |= ActivityInfo.CONFIG_ORIENTATION;
final Configuration newConfig = new Configuration(mActivity.getConfiguration());
- newConfig.orientation = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT
- ? Configuration.ORIENTATION_LANDSCAPE
- : Configuration.ORIENTATION_PORTRAIT;
+ final int shortSide = Math.min(newConfig.screenWidthDp, newConfig.screenHeightDp);
+ final int longSide = Math.max(newConfig.screenWidthDp, newConfig.screenHeightDp);
+ if (newConfig.orientation == ORIENTATION_PORTRAIT) {
+ newConfig.orientation = ORIENTATION_LANDSCAPE;
+ newConfig.screenWidthDp = longSide;
+ newConfig.screenHeightDp = shortSide;
+ } else {
+ newConfig.orientation = ORIENTATION_PORTRAIT;
+ newConfig.screenWidthDp = shortSide;
+ newConfig.screenHeightDp = longSide;
+ }
mTask.onConfigurationChanged(newConfig);
@@ -457,7 +484,7 @@
@Test
public void testShouldPauseWhenMakeClientVisible() {
ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
- topActivity.changeWindowTranslucency(false);
+ topActivity.setOccludesParent(false);
mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
mActivity.makeClientVisible();
assertEquals(STARTED, mActivity.getState());
@@ -468,6 +495,7 @@
setupDisplayContentForCompatDisplayInsets();
final int decorHeight = 200; // e.g. The device has cutout.
final DisplayPolicy policy = setupDisplayAndParentSize(600, 800).getDisplayPolicy();
+ spyOn(policy);
doAnswer(invocationOnMock -> {
final int rotation = invocationOnMock.<Integer>getArgument(0);
final Rect insets = invocationOnMock.<Rect>getArgument(4);
@@ -482,7 +510,7 @@
doReturn(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)
.when(mActivity.mAppWindowToken).getOrientationIgnoreVisibility();
- mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+ mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
mActivity.info.minAspectRatio = mActivity.info.maxAspectRatio = 1;
ensureActivityConfiguration();
// The parent configuration doesn't change since the first resolved configuration, so the
@@ -506,19 +534,28 @@
@Test
public void testSizeCompatMode_FixedScreenConfigurationWhenMovingToDisplay() {
// Initialize different bounds on a new display.
- final ActivityDisplay newDisplay = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP);
- newDisplay.getWindowConfiguration().setAppBounds(new Rect(0, 0, 1000, 2000));
- newDisplay.getConfiguration().densityDpi = 300;
+ final Rect newDisplayBounds = new Rect(0, 0, 1000, 2000);
+ DisplayInfo info = new DisplayInfo();
+ mService.mContext.getDisplay().getDisplayInfo(info);
+ info.logicalWidth = newDisplayBounds.width();
+ info.logicalHeight = newDisplayBounds.height();
+ info.logicalDensityDpi = 300;
+
+ final ActivityDisplay newDisplay =
+ addNewActivityDisplayAt(info, ActivityDisplay.POSITION_TOP);
mTask.getConfiguration().densityDpi = 200;
- prepareFixedAspectRatioUnresizableActivity();
+ mActivity = new ActivityBuilder(mService)
+ .setTask(mTask)
+ .setResizeMode(RESIZE_MODE_UNRESIZEABLE)
+ .setMaxAspectRatio(1.5f)
+ .build();
final Rect originalBounds = new Rect(mActivity.getBounds());
final int originalDpi = mActivity.getConfiguration().densityDpi;
// Move the non-resizable activity to the new display.
mStack.reparent(newDisplay, true /* onTop */, false /* displayRemoved */);
- ensureActivityConfiguration();
assertEquals(originalBounds, mActivity.getBounds());
assertEquals(originalDpi, mActivity.getConfiguration().densityDpi);
@@ -531,9 +568,9 @@
when(mActivity.mAppWindowToken.getOrientationIgnoreVisibility()).thenReturn(
ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
mTask.getWindowConfiguration().setAppBounds(mStack.getDisplay().getBounds());
- mTask.getConfiguration().orientation = Configuration.ORIENTATION_PORTRAIT;
+ mTask.getConfiguration().orientation = ORIENTATION_PORTRAIT;
mActivity.info.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
- mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+ mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
ensureActivityConfiguration();
final Rect originalBounds = new Rect(mActivity.getBounds());
@@ -579,7 +616,7 @@
mTask.getWindowConfiguration().setAppBounds(new Rect(0, 0, 600, 1200));
// Simulate the display changes orientation.
- doReturn(ActivityInfo.CONFIG_SCREEN_SIZE | ActivityInfo.CONFIG_ORIENTATION
+ doReturn(ActivityInfo.CONFIG_SCREEN_SIZE | CONFIG_ORIENTATION
| ActivityInfo.CONFIG_WINDOW_CONFIGURATION)
.when(display).getLastOverrideConfigurationChanges();
mActivity.onConfigurationChanged(mTask.getConfiguration());
@@ -754,24 +791,17 @@
/** Setup {@link #mActivity} as a size-compat-mode-able activity without fixed orientation. */
private void prepareFixedAspectRatioUnresizableActivity() {
setupDisplayContentForCompatDisplayInsets();
- when(mActivity.mAppWindowToken.getOrientationIgnoreVisibility()).thenReturn(
- ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
- mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+ mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
mActivity.info.maxAspectRatio = 1.5f;
ensureActivityConfiguration();
}
private void setupDisplayContentForCompatDisplayInsets() {
final Rect displayBounds = mStack.getDisplay().getBounds();
- final DisplayContent displayContent = setupDisplayAndParentSize(
- displayBounds.width(), displayBounds.height());
- doReturn(mock(DisplayPolicy.class)).when(displayContent).getDisplayPolicy();
- doReturn(mock(WmDisplayCutout.class)).when(displayContent)
- .calculateDisplayCutoutForRotation(anyInt());
+ setupDisplayAndParentSize(displayBounds.width(), displayBounds.height());
}
private DisplayContent setupDisplayAndParentSize(int width, int height) {
- // The DisplayContent is already a mocked object.
final DisplayContent displayContent = mStack.getDisplay().mDisplayContent;
displayContent.mBaseDisplayWidth = width;
displayContent.mBaseDisplayHeight = height;
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index e5278d8..ff7b1fa 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -29,7 +29,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.server.wm.ActivityStack.ActivityState.DESTROYING;
import static com.android.server.wm.ActivityStack.ActivityState.FINISHING;
@@ -44,6 +44,7 @@
import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE;
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
+import static com.android.server.wm.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT;
import static com.google.common.truth.Truth.assertThat;
@@ -83,8 +84,9 @@
@Before
public void setUp() throws Exception {
mDefaultDisplay = mRootActivityContainer.getDefaultDisplay();
- mStack = spy(mDefaultDisplay.createStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD,
- true /* onTop */));
+ mStack = mDefaultDisplay.createStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD,
+ true /* onTop */);
+ spyOn(mStack);
mTask = new TaskBuilder(mSupervisor).setStack(mStack).build();
}
@@ -140,10 +142,8 @@
final ActivityStack destStack = mRootActivityContainer.getDefaultDisplay().createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- final TaskRecord destTask = new TaskBuilder(mSupervisor).setStack(destStack).build();
-
- mTask.removeActivity(r);
- destTask.addActivityToTop(r);
+ mTask.reparent(destStack, true /*toTop*/, REPARENT_MOVE_STACK_TO_FRONT, false, false,
+ "testResumedActivityFromActivityReparenting");
assertNull(mStack.getResumedActivity());
assertEquals(r, destStack.getResumedActivity());
@@ -313,45 +313,50 @@
@Test
public void testShouldBeVisible_Fullscreen() {
- final TestActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+ final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
final ActivityStack pinnedStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ // Add an activity to the pinned stack so it isn't considered empty for visibility check.
+ final ActivityRecord pinnedActivity = new ActivityBuilder(mService)
+ .setCreateTask(true)
+ .setStack(pinnedStack)
+ .build();
assertTrue(homeStack.shouldBeVisible(null /* starting */));
assertTrue(pinnedStack.shouldBeVisible(null /* starting */));
- final TestActivityStack fullscreenStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+ final ActivityStack fullscreenStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
// Home stack shouldn't be visible behind an opaque fullscreen stack, but pinned stack
// should be visible since it is always on-top.
- fullscreenStack.setIsTranslucent(false);
+ doReturn(false).when(fullscreenStack).isStackTranslucent(any());
assertFalse(homeStack.shouldBeVisible(null /* starting */));
assertTrue(pinnedStack.shouldBeVisible(null /* starting */));
assertTrue(fullscreenStack.shouldBeVisible(null /* starting */));
// Home stack should be visible behind a translucent fullscreen stack.
- fullscreenStack.setIsTranslucent(true);
+ doReturn(true).when(fullscreenStack).isStackTranslucent(any());
assertTrue(homeStack.shouldBeVisible(null /* starting */));
assertTrue(pinnedStack.shouldBeVisible(null /* starting */));
}
@Test
public void testShouldBeVisible_SplitScreen() {
- final TestActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+ final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
// Home stack should always be fullscreen for this test.
- homeStack.setSupportsSplitScreen(false);
- final TestActivityStack splitScreenPrimary =
+ doReturn(false).when(homeStack).supportsSplitScreenWindowingMode();
+ final ActivityStack splitScreenPrimary =
createStackForShouldBeVisibleTest(mDefaultDisplay,
WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- final TestActivityStack splitScreenSecondary =
+ final ActivityStack splitScreenSecondary =
createStackForShouldBeVisibleTest(mDefaultDisplay,
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
// Home stack shouldn't be visible if both halves of split-screen are opaque.
- splitScreenPrimary.setIsTranslucent(false);
- splitScreenSecondary.setIsTranslucent(false);
+ doReturn(false).when(splitScreenPrimary).isStackTranslucent(any());
+ doReturn(false).when(splitScreenSecondary).isStackTranslucent(any());
assertFalse(homeStack.shouldBeVisible(null /* starting */));
assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */));
assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */));
@@ -362,7 +367,7 @@
splitScreenSecondary.getVisibility(null /* starting */));
// Home stack should be visible if one of the halves of split-screen is translucent.
- splitScreenPrimary.setIsTranslucent(true);
+ doReturn(true).when(splitScreenPrimary).isStackTranslucent(any());
assertTrue(homeStack.shouldBeVisible(null /* starting */));
assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */));
assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */));
@@ -373,12 +378,12 @@
assertEquals(STACK_VISIBILITY_VISIBLE,
splitScreenSecondary.getVisibility(null /* starting */));
- final TestActivityStack splitScreenSecondary2 =
+ final ActivityStack splitScreenSecondary2 =
createStackForShouldBeVisibleTest(mDefaultDisplay,
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
// First split-screen secondary shouldn't be visible behind another opaque split-split
// secondary.
- splitScreenSecondary2.setIsTranslucent(false);
+ doReturn(false).when(splitScreenSecondary2).isStackTranslucent(any());
assertFalse(splitScreenSecondary.shouldBeVisible(null /* starting */));
assertTrue(splitScreenSecondary2.shouldBeVisible(null /* starting */));
assertEquals(STACK_VISIBILITY_INVISIBLE,
@@ -388,7 +393,7 @@
// First split-screen secondary should be visible behind another translucent split-screen
// secondary.
- splitScreenSecondary2.setIsTranslucent(true);
+ doReturn(true).when(splitScreenSecondary2).isStackTranslucent(any());
assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */));
assertTrue(splitScreenSecondary2.shouldBeVisible(null /* starting */));
assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
@@ -396,11 +401,11 @@
assertEquals(STACK_VISIBILITY_VISIBLE,
splitScreenSecondary2.getVisibility(null /* starting */));
- final TestActivityStack assistantStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+ final ActivityStack assistantStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_ASSISTANT, true /* onTop */);
// Split-screen stacks shouldn't be visible behind an opaque fullscreen stack.
- assistantStack.setIsTranslucent(false);
+ doReturn(false).when(assistantStack).isStackTranslucent(any());
assertTrue(assistantStack.shouldBeVisible(null /* starting */));
assertFalse(splitScreenPrimary.shouldBeVisible(null /* starting */));
assertFalse(splitScreenSecondary.shouldBeVisible(null /* starting */));
@@ -415,7 +420,7 @@
splitScreenSecondary2.getVisibility(null /* starting */));
// Split-screen stacks should be visible behind a translucent fullscreen stack.
- assistantStack.setIsTranslucent(true);
+ doReturn(true).when(assistantStack).isStackTranslucent(any());
assertTrue(assistantStack.shouldBeVisible(null /* starting */));
assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */));
assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */));
@@ -430,9 +435,9 @@
splitScreenSecondary2.getVisibility(null /* starting */));
// Assistant stack shouldn't be visible behind translucent split-screen stack
- assistantStack.setIsTranslucent(false);
- splitScreenPrimary.setIsTranslucent(true);
- splitScreenSecondary2.setIsTranslucent(true);
+ doReturn(false).when(assistantStack).isStackTranslucent(any());
+ doReturn(true).when(splitScreenPrimary).isStackTranslucent(any());
+ doReturn(true).when(splitScreenSecondary2).isStackTranslucent(any());
splitScreenSecondary2.moveToFront("testShouldBeVisible_SplitScreen");
splitScreenPrimary.moveToFront("testShouldBeVisible_SplitScreen");
assertFalse(assistantStack.shouldBeVisible(null /* starting */));
@@ -450,10 +455,10 @@
@Test
public void testGetVisibility_FullscreenBehindTranslucent() {
- final TestActivityStack bottomStack =
+ final ActivityStack bottomStack =
createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
false /* translucent */);
- final TestActivityStack translucentStack =
+ final ActivityStack translucentStack =
createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
true /* translucent */);
@@ -465,13 +470,13 @@
@Test
public void testGetVisibility_FullscreenBehindTranslucentAndOpaque() {
- final TestActivityStack bottomStack =
+ final ActivityStack bottomStack =
createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
false /* translucent */);
- final TestActivityStack translucentStack =
+ final ActivityStack translucentStack =
createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
true /* translucent */);
- final TestActivityStack opaqueStack =
+ final ActivityStack opaqueStack =
createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
false /* translucent */);
@@ -483,13 +488,13 @@
@Test
public void testGetVisibility_FullscreenBehindOpaqueAndTranslucent() {
- final TestActivityStack bottomStack =
+ final ActivityStack bottomStack =
createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
false /* translucent */);
- final TestActivityStack opaqueStack =
+ final ActivityStack opaqueStack =
createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
false /* translucent */);
- final TestActivityStack translucentStack =
+ final ActivityStack translucentStack =
createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
true /* translucent */);
@@ -502,10 +507,10 @@
@Test
public void testGetVisibility_FullscreenTranslucentBehindTranslucent() {
- final TestActivityStack bottomTranslucentStack =
+ final ActivityStack bottomTranslucentStack =
createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
true /* translucent */);
- final TestActivityStack translucentStack =
+ final ActivityStack translucentStack =
createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
true /* translucent */);
@@ -517,10 +522,10 @@
@Test
public void testGetVisibility_FullscreenTranslucentBehindOpaque() {
- final TestActivityStack bottomTranslucentStack =
+ final ActivityStack bottomTranslucentStack =
createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
true /* translucent */);
- final TestActivityStack opaqueStack =
+ final ActivityStack opaqueStack =
createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
false /* translucent */);
@@ -531,10 +536,10 @@
@Test
public void testGetVisibility_FullscreenBehindTranslucentAndPip() {
- final TestActivityStack bottomStack =
+ final ActivityStack bottomStack =
createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
false /* translucent */);
- final TestActivityStack translucentStack =
+ final ActivityStack translucentStack =
createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
true /* translucent */);
final ActivityStack pinnedStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
@@ -544,22 +549,34 @@
bottomStack.getVisibility(null /* starting */));
assertEquals(STACK_VISIBILITY_VISIBLE,
translucentStack.getVisibility(null /* starting */));
+ // Add an activity to the pinned stack so it isn't considered empty for visibility check.
+ final ActivityRecord pinnedActivity = new ActivityBuilder(mService)
+ .setCreateTask(true)
+ .setStack(pinnedStack)
+ .build();
assertEquals(STACK_VISIBILITY_VISIBLE, pinnedStack.getVisibility(null /* starting */));
}
@Test
public void testShouldBeVisible_Finishing() {
- final TestActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+ final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
- final TestActivityStack translucentStack = createStackForShouldBeVisibleTest(
+ ActivityRecord topRunningHomeActivity = homeStack.topRunningActivityLocked();
+ if (topRunningHomeActivity == null) {
+ topRunningHomeActivity = new ActivityBuilder(mService)
+ .setStack(homeStack)
+ .setCreateTask(true)
+ .build();
+ }
+
+ final ActivityStack translucentStack = createStackForShouldBeVisibleTest(
mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
- translucentStack.setIsTranslucent(true);
+ doReturn(true).when(translucentStack).isStackTranslucent(any());
assertTrue(homeStack.shouldBeVisible(null /* starting */));
assertTrue(translucentStack.shouldBeVisible(null /* starting */));
- final ActivityRecord topRunningHomeActivity = homeStack.topRunningActivityLocked();
topRunningHomeActivity.finishing = true;
final ActivityRecord topRunningTranslucentActivity =
translucentStack.topRunningActivityLocked();
@@ -577,13 +594,13 @@
public void testMoveHomeStackBehindBottomMostVisibleStack_NoMoveHomeBehindFullscreen() {
mDefaultDisplay.removeChild(mStack);
- final TestActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+ final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
- final TestActivityStack fullscreenStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+ final ActivityStack fullscreenStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- homeStack.setIsTranslucent(false);
- fullscreenStack.setIsTranslucent(false);
+ doReturn(false).when(homeStack).isStackTranslucent(any());
+ doReturn(false).when(fullscreenStack).isStackTranslucent(any());
// Ensure that we don't move the home stack if it is already behind the top fullscreen stack
int homeStackIndex = mDefaultDisplay.getIndexOf(homeStack);
@@ -596,13 +613,13 @@
public void testMoveHomeStackBehindBottomMostVisibleStack_NoMoveHomeBehindTranslucent() {
mDefaultDisplay.removeChild(mStack);
- final TestActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+ final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
- final TestActivityStack fullscreenStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+ final ActivityStack fullscreenStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- homeStack.setIsTranslucent(false);
- fullscreenStack.setIsTranslucent(true);
+ doReturn(false).when(homeStack).isStackTranslucent(any());
+ doReturn(true).when(fullscreenStack).isStackTranslucent(any());
// Ensure that we don't move the home stack if it is already behind the top fullscreen stack
int homeStackIndex = mDefaultDisplay.getIndexOf(homeStack);
@@ -615,13 +632,13 @@
public void testMoveHomeStackBehindBottomMostVisibleStack_NoMoveHomeOnTop() {
mDefaultDisplay.removeChild(mStack);
- final TestActivityStack fullscreenStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+ final ActivityStack fullscreenStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- final TestActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+ final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
- homeStack.setIsTranslucent(false);
- fullscreenStack.setIsTranslucent(false);
+ doReturn(false).when(homeStack).isStackTranslucent(any());
+ doReturn(false).when(fullscreenStack).isStackTranslucent(any());
// Ensure we don't move the home stack if it is already on top
int homeStackIndex = mDefaultDisplay.getIndexOf(homeStack);
@@ -634,20 +651,20 @@
public void testMoveHomeStackBehindBottomMostVisibleStack_MoveHomeBehindFullscreen() {
mDefaultDisplay.removeChild(mStack);
- final TestActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+ final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
- final TestActivityStack fullscreenStack1 = createStackForShouldBeVisibleTest(
+ final ActivityStack fullscreenStack1 = createStackForShouldBeVisibleTest(
mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
- final TestActivityStack fullscreenStack2 = createStackForShouldBeVisibleTest(
+ final ActivityStack fullscreenStack2 = createStackForShouldBeVisibleTest(
mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
final ActivityStack pinnedStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- homeStack.setIsTranslucent(false);
- fullscreenStack1.setIsTranslucent(false);
- fullscreenStack2.setIsTranslucent(false);
+ doReturn(false).when(homeStack).isStackTranslucent(any());
+ doReturn(false).when(fullscreenStack1).isStackTranslucent(any());
+ doReturn(false).when(fullscreenStack2).isStackTranslucent(any());
// Ensure that we move the home stack behind the bottom most fullscreen stack, ignoring the
// pinned stack
@@ -661,18 +678,18 @@
testMoveHomeStackBehindBottomMostVisibleStack_MoveHomeBehindFullscreenAndTranslucent() {
mDefaultDisplay.removeChild(mStack);
- final TestActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+ final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
- final TestActivityStack fullscreenStack1 = createStackForShouldBeVisibleTest(
+ final ActivityStack fullscreenStack1 = createStackForShouldBeVisibleTest(
mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
- final TestActivityStack fullscreenStack2 = createStackForShouldBeVisibleTest(
+ final ActivityStack fullscreenStack2 = createStackForShouldBeVisibleTest(
mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
- homeStack.setIsTranslucent(false);
- fullscreenStack1.setIsTranslucent(false);
- fullscreenStack2.setIsTranslucent(true);
+ doReturn(false).when(homeStack).isStackTranslucent(any());
+ doReturn(false).when(fullscreenStack1).isStackTranslucent(any());
+ doReturn(true).when(fullscreenStack2).isStackTranslucent(any());
// Ensure that we move the home stack behind the bottom most non-translucent fullscreen
// stack
@@ -685,18 +702,18 @@
public void testMoveHomeStackBehindStack_BehindHomeStack() {
mDefaultDisplay.removeChild(mStack);
- final TestActivityStack fullscreenStack1 = createStackForShouldBeVisibleTest(
+ final ActivityStack fullscreenStack1 = createStackForShouldBeVisibleTest(
mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
- final TestActivityStack fullscreenStack2 = createStackForShouldBeVisibleTest(
+ final ActivityStack fullscreenStack2 = createStackForShouldBeVisibleTest(
mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
- final TestActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+ final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
- homeStack.setIsTranslucent(false);
- fullscreenStack1.setIsTranslucent(false);
- fullscreenStack2.setIsTranslucent(false);
+ doReturn(false).when(homeStack).isStackTranslucent(any());
+ doReturn(false).when(fullscreenStack1).isStackTranslucent(any());
+ doReturn(false).when(fullscreenStack2).isStackTranslucent(any());
// Ensure we don't move the home stack behind itself
int homeStackIndex = mDefaultDisplay.getIndexOf(homeStack);
@@ -708,19 +725,19 @@
public void testMoveHomeStackBehindStack() {
mDefaultDisplay.removeChild(mStack);
- final TestActivityStack fullscreenStack1 = createStackForShouldBeVisibleTest(
+ final ActivityStack fullscreenStack1 = createStackForShouldBeVisibleTest(
mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
- final TestActivityStack fullscreenStack2 = createStackForShouldBeVisibleTest(
+ final ActivityStack fullscreenStack2 = createStackForShouldBeVisibleTest(
mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
- final TestActivityStack fullscreenStack3 = createStackForShouldBeVisibleTest(
+ final ActivityStack fullscreenStack3 = createStackForShouldBeVisibleTest(
mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
- final TestActivityStack fullscreenStack4 = createStackForShouldBeVisibleTest(
+ final ActivityStack fullscreenStack4 = createStackForShouldBeVisibleTest(
mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
- final TestActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+ final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
mDefaultDisplay.moveStackBehindStack(homeStack, fullscreenStack1);
@@ -735,13 +752,13 @@
@Test
public void testSetAlwaysOnTop() {
- final TestActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+ final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
final ActivityStack pinnedStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
assertEquals(pinnedStack, mDefaultDisplay.getStackAbove(homeStack));
- final TestActivityStack alwaysOnTopStack = createStackForShouldBeVisibleTest(
+ final ActivityStack alwaysOnTopStack = createStackForShouldBeVisibleTest(
mDefaultDisplay, WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
alwaysOnTopStack.setAlwaysOnTop(true);
@@ -749,13 +766,13 @@
// Ensure (non-pinned) always on top stack is put below pinned stack.
assertEquals(pinnedStack, mDefaultDisplay.getStackAbove(alwaysOnTopStack));
- final TestActivityStack nonAlwaysOnTopStack = createStackForShouldBeVisibleTest(
+ final ActivityStack nonAlwaysOnTopStack = createStackForShouldBeVisibleTest(
mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
// Ensure non always on top stack is put below always on top stacks.
assertEquals(alwaysOnTopStack, mDefaultDisplay.getStackAbove(nonAlwaysOnTopStack));
- final TestActivityStack alwaysOnTopStack2 = createStackForShouldBeVisibleTest(
+ final ActivityStack alwaysOnTopStack2 = createStackForShouldBeVisibleTest(
mDefaultDisplay, WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
alwaysOnTopStack2.setAlwaysOnTop(true);
@@ -780,18 +797,18 @@
@Test
public void testSplitScreenMoveToFront() {
- final TestActivityStack splitScreenPrimary = createStackForShouldBeVisibleTest(
+ final ActivityStack splitScreenPrimary = createStackForShouldBeVisibleTest(
mDefaultDisplay, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
- final TestActivityStack splitScreenSecondary = createStackForShouldBeVisibleTest(
+ final ActivityStack splitScreenSecondary = createStackForShouldBeVisibleTest(
mDefaultDisplay, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
- final TestActivityStack assistantStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+ final ActivityStack assistantStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_ASSISTANT, true /* onTop */);
- splitScreenPrimary.setIsTranslucent(false);
- splitScreenSecondary.setIsTranslucent(false);
- assistantStack.setIsTranslucent(false);
+ doReturn(false).when(splitScreenPrimary).isStackTranslucent(any());
+ doReturn(false).when(splitScreenSecondary).isStackTranslucent(any());
+ doReturn(false).when(assistantStack).isStackTranslucent(any());
assertFalse(splitScreenPrimary.shouldBeVisible(null /* starting */));
assertFalse(splitScreenSecondary.shouldBeVisible(null /* starting */));
@@ -804,18 +821,18 @@
assertFalse(assistantStack.shouldBeVisible(null /* starting */));
}
- private TestActivityStack createStandardStackForVisibilityTest(int windowingMode,
+ private ActivityStack createStandardStackForVisibilityTest(int windowingMode,
boolean translucent) {
- final TestActivityStack stack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+ final ActivityStack stack = createStackForShouldBeVisibleTest(mDefaultDisplay,
windowingMode, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- stack.setIsTranslucent(translucent);
+ doReturn(translucent).when(stack).isStackTranslucent(any());
return stack;
}
@SuppressWarnings("TypeParameterUnusedInFormals")
private <T extends ActivityStack> T createStackForShouldBeVisibleTest(
ActivityDisplay display, int windowingMode, int activityType, boolean onTop) {
- final T stack;
+ final ActivityStack stack;
if (activityType == ACTIVITY_TYPE_HOME) {
// Home stack and activity are created in ActivityTestsBase#setupActivityManagerService
stack = mDefaultDisplay.getStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
@@ -825,11 +842,15 @@
mDefaultDisplay.positionChildAtBottom(stack);
}
} else {
- stack = display.createStack(windowingMode, activityType, onTop);
- final ActivityRecord r = new ActivityBuilder(mService).setUid(0).setStack(stack)
- .setCreateTask(true).build();
+ stack = new StackBuilder(mRootActivityContainer)
+ .setDisplay(display)
+ .setWindowingMode(windowingMode)
+ .setActivityType(activityType)
+ .setOnTop(onTop)
+ .setCreateActivity(true)
+ .build();
}
- return stack;
+ return (T) stack;
}
@Test
@@ -961,11 +982,16 @@
@Test
public void testAdjustFocusedStackToHomeWhenNoActivity() {
+ final ActivityStack homeStask = mDefaultDisplay.getHomeStack();
+ TaskRecord homeTask = homeStask.topTask();
+ if (homeTask == null) {
+ // Create home task if there isn't one.
+ homeTask = new TaskBuilder(mSupervisor).setStack(homeStask).build();
+ }
+
final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
mStack.moveToFront("testAdjustFocusedStack");
- final ActivityStack homeStask = mDefaultDisplay.getHomeStack();
- final TaskRecord homeTask = homeStask.topTask();
// Simulate that home activity has not been started or is force-stopped.
homeStask.removeTask(homeTask, "testAdjustFocusedStack", REMOVE_TASK_MODE_DESTROYING);
@@ -981,6 +1007,14 @@
final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
+ ActivityRecord activity = homeStack.topRunningActivityLocked();
+ if (activity == null) {
+ activity = new ActivityBuilder(mService)
+ .setStack(homeStack)
+ .setCreateTask(true)
+ .build();
+ }
+
// Home stack should not be destroyed immediately.
final ActivityRecord activity1 = finishCurrentActivity(homeStack);
assertEquals(FINISHING, activity1.getState());
@@ -1068,7 +1102,7 @@
public void testStackOrderChangedOnPositionStack() {
StackOrderChangedListener listener = new StackOrderChangedListener();
try {
- final TestActivityStack fullscreenStack1 = createStackForShouldBeVisibleTest(
+ final ActivityStack fullscreenStack1 = createStackForShouldBeVisibleTest(
mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
mDefaultDisplay.registerStackOrderChangedListener(listener);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 3d94467..81fbfe4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -79,6 +79,7 @@
import androidx.test.filters.SmallTest;
import com.android.server.wm.LaunchParamsController.LaunchParamsModifier;
+import com.android.server.wm.utils.MockTracker;
import org.junit.Before;
import org.junit.Test;
@@ -186,6 +187,19 @@
verifyStartActivityPreconditions(preconditions, 0 /*launchFlags*/, expectedResult);
}
+ private void verifyStartActivityPreconditions(int preconditions, int launchFlags,
+ int expectedResult) {
+ // We track mocks created here because this is used in a single test
+ // (testStartActivityPreconditions) as a specific case, and mocks created inside it won't be
+ // used for other cases. To avoid extensive memory usage, we clean up all used mocks after
+ // each case. This is necessary because usually we only clean up mocks after a test
+ // finishes, but this test creates too many mocks that the intermediate memory usage can be
+ // ~0.8 GiB and thus very susceptible to OutOfMemoryException.
+ try (MockTracker tracker = new MockTracker()) {
+ verifyStartActivityPreconditionsUntracked(preconditions, launchFlags, expectedResult);
+ }
+ }
+
/**
* Excercises how the {@link ActivityStarter} reacts to various preconditions. The caller
* provides a bitmask of all the set conditions (such as {@link #PRECONDITION_NO_CALLER_APP})
@@ -197,7 +211,7 @@
* @param launchFlags The launch flags to be provided by the launch {@link Intent}.
* @param expectedResult The expected result from the launch.
*/
- private void verifyStartActivityPreconditions(int preconditions, int launchFlags,
+ private void verifyStartActivityPreconditionsUntracked(int preconditions, int launchFlags,
int expectedResult) {
final ActivityTaskManagerService service = mService;
final IPackageManager packageManager = mock(IPackageManager.class);
@@ -329,9 +343,6 @@
any(), any(), any(), anyInt(), anyInt(), anyInt(), any(),
anyBoolean(), anyBoolean(), any(), any(), any());
- // Use factory that only returns spy task.
- mockTaskRecordFactory();
-
if (mockGetLaunchStack) {
// Instrument the stack and task used.
final ActivityStack stack = mRootActivityContainer.getDefaultDisplay().createStack(
@@ -482,7 +493,7 @@
@Test
public void testTaskModeViolation() {
final ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay();
- ((TestActivityDisplay) display).removeAllTasks();
+ display.removeAllTasks();
assertNoTasks(display);
final ActivityStarter starter = prepareStarter(0);
@@ -676,18 +687,27 @@
doReturn(isCallingUidDeviceOwner).when(mService).isDeviceOwner(callingUid);
final ActivityOptions options = spy(ActivityOptions.makeBasic());
+ ActivityRecord[] outActivity = new ActivityRecord[1];
ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK)
.setCallingPackage("com.whatever.dude")
.setCaller(caller)
.setCallingUid(callingUid)
.setRealCallingUid(realCallingUid)
- .setActivityOptions(new SafeActivityOptions(options));
+ .setActivityOptions(new SafeActivityOptions(options))
+ .setOutActivity(outActivity);
final int result = starter.setReason("testBackgroundActivityStarts_" + name).execute();
assertEquals(ActivityStarter.getExternalResult(
shouldHaveAborted ? START_ABORTED : START_SUCCESS), result);
verify(options, times(shouldHaveAborted ? 1 : 0)).abort();
+
+ final ActivityRecord startedActivity = outActivity[0];
+ if (startedActivity != null && startedActivity.getTaskRecord() != null) {
+ // Remove the activity so it doesn't interfere with with subsequent activity launch
+ // tests from this method.
+ startedActivity.getTaskRecord().removeActivity(startedActivity);
+ }
}
/**
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
index d8a9bb0..297aa7e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
@@ -45,8 +45,7 @@
/** Verify that activity is finished correctly upon request. */
@Test
public void testActivityFinish() {
- final TestActivityStack stack =
- (TestActivityStack) new StackBuilder(mRootActivityContainer).build();
+ final ActivityStack stack = new StackBuilder(mRootActivityContainer).build();
final ActivityRecord activity = stack.getChildAt(0).getTopActivity();
assertTrue("Activity must be finished", mService.finishActivity(activity.appToken,
0 /* resultCode */, null /* resultData */,
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index ab2da2b..a5dc241 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -16,96 +16,58 @@
package com.android.server.wm;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyString;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doCallRealMethod;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
-import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
-import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
-import android.app.ActivityManagerInternal;
import android.app.ActivityOptions;
-import android.app.AppOpsManager;
import android.app.IApplicationThread;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
-import android.content.pm.IPackageManager;
-import android.content.pm.PackageManagerInternal;
import android.content.res.Configuration;
import android.graphics.Rect;
-import android.hardware.display.DisplayManager;
-import android.hardware.display.DisplayManagerGlobal;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.PowerManager;
-import android.os.Process;
import android.os.UserHandle;
import android.service.voice.IVoiceInteractionSession;
import android.testing.DexmakerShareClassLoaderRule;
-import android.view.Display;
import android.view.DisplayInfo;
-import com.android.internal.app.IVoiceInteractor;
import com.android.server.AttributeCache;
-import com.android.server.ServiceThread;
-import com.android.server.am.ActivityManagerService;
-import com.android.server.am.PendingIntentController;
-import com.android.server.appop.AppOpsService;
-import com.android.server.firewall.IntentFirewall;
-import com.android.server.policy.PermissionPolicyInternal;
-import com.android.server.uri.UriGrantsManagerInternal;
-import com.android.server.wm.TaskRecord.TaskRecordFactory;
-import com.android.server.wm.utils.MockTracker;
-import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
-import org.mockito.invocation.InvocationOnMock;
-
-import java.io.File;
-import java.util.List;
-import java.util.function.Consumer;
/**
* A base class to handle common operations in activity related unit tests.
*/
class ActivityTestsBase {
- private static int sNextDisplayId = DEFAULT_DISPLAY + 1;
@Rule
public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
new DexmakerShareClassLoaderRule();
+ @Rule
+ public final SystemServicesTestRule mSystemServicesTestRule = new SystemServicesTestRule();
+
final Context mContext = getInstrumentation().getTargetContext();
- final TestInjector mTestInjector = new TestInjector(mContext);
ActivityTaskManagerService mService;
RootActivityContainer mRootActivityContainer;
ActivityStackSupervisor mSupervisor;
- private MockTracker mMockTracker;
-
// Default package name
static final String DEFAULT_COMPONENT_PACKAGE_NAME = "com.foo";
@@ -119,37 +81,18 @@
@Before
public void setUpBase() {
- mMockTracker = new MockTracker();
-
- mTestInjector.setUp();
-
- mService = new TestActivityTaskManagerService(mContext);
+ mService = mSystemServicesTestRule.getActivityTaskManagerService();
mSupervisor = mService.mStackSupervisor;
mRootActivityContainer = mService.mRootActivityContainer;
}
- @After
- public void tearDownBase() {
- mTestInjector.tearDown();
- if (mService != null) {
- mService.setWindowManager(null);
- mService = null;
- }
- if (sMockWindowManagerService != null) {
- reset(sMockWindowManagerService);
- }
-
- mMockTracker.close();
- mMockTracker = null;
- }
-
/** Creates a {@link TestActivityDisplay}. */
TestActivityDisplay createNewActivityDisplay() {
- return TestActivityDisplay.create(mSupervisor, sNextDisplayId++);
+ return TestActivityDisplay.create(mSupervisor);
}
TestActivityDisplay createNewActivityDisplay(DisplayInfo info) {
- return TestActivityDisplay.create(mSupervisor, sNextDisplayId++, info);
+ return TestActivityDisplay.create(mSupervisor, info);
}
/** Creates and adds a {@link TestActivityDisplay} to supervisor at the given position. */
@@ -166,25 +109,9 @@
return display;
}
- /**
- * Delegates task creation to {@link #TaskBuilder} to avoid the dependency of window hierarchy
- * when starting activity in unit tests.
- */
- void mockTaskRecordFactory(Consumer<TaskBuilder> taskBuilderSetup) {
- final TaskBuilder taskBuilder = new TaskBuilder(mSupervisor).setCreateStack(false);
- if (taskBuilderSetup != null) {
- taskBuilderSetup.accept(taskBuilder);
- }
- final TaskRecord task = taskBuilder.build();
- final TaskRecordFactory factory = mock(TaskRecordFactory.class);
- TaskRecord.setTaskRecordFactory(factory);
- doReturn(task).when(factory).create(any() /* service */, anyInt() /* taskId */,
- any() /* info */, any() /* intent */, any() /* voiceSession */,
- any() /* voiceInteractor */);
- }
-
- void mockTaskRecordFactory() {
- mockTaskRecordFactory(null /* taskBuilderSetup */);
+ /** Sets the default minimum task size to 1 so that tests can use small task sizes */
+ public void removeGlobalMinSizeRestriction() {
+ mService.mRootActivityContainer.mDefaultMinSizeOfResizeableTaskDp = 1;
}
/**
@@ -204,6 +131,11 @@
private ActivityStack mStack;
private int mActivityFlags;
private int mLaunchMode;
+ private int mResizeMode = RESIZE_MODE_RESIZEABLE;
+ private float mMaxAspectRatio;
+ private int mScreenOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
+ private boolean mLaunchTaskBehind;
+ private int mConfigChanges;
ActivityBuilder(ActivityTaskManagerService service) {
mService = service;
@@ -254,6 +186,31 @@
return this;
}
+ ActivityBuilder setResizeMode(int resizeMode) {
+ mResizeMode = resizeMode;
+ return this;
+ }
+
+ ActivityBuilder setMaxAspectRatio(float maxAspectRatio) {
+ mMaxAspectRatio = maxAspectRatio;
+ return this;
+ }
+
+ ActivityBuilder setScreenOrientation(int screenOrientation) {
+ mScreenOrientation = screenOrientation;
+ return this;
+ }
+
+ ActivityBuilder setLaunchTaskBehind(boolean launchTaskBehind) {
+ mLaunchTaskBehind = launchTaskBehind;
+ return this;
+ }
+
+ ActivityBuilder setConfigChanges(int configChanges) {
+ mConfigChanges = configChanges;
+ return this;
+ }
+
ActivityRecord build() {
if (mComponent == null) {
final int id = sCurrentActivityId++;
@@ -279,24 +236,31 @@
}
aInfo.flags |= mActivityFlags;
aInfo.launchMode = mLaunchMode;
+ aInfo.resizeMode = mResizeMode;
+ aInfo.maxAspectRatio = mMaxAspectRatio;
+ aInfo.screenOrientation = mScreenOrientation;
+ aInfo.configChanges |= mConfigChanges;
+
+ ActivityOptions options = null;
+ if (mLaunchTaskBehind) {
+ options = ActivityOptions.makeTaskLaunchBehind();
+ }
final ActivityRecord activity = new ActivityRecord(mService, null /* caller */,
0 /* launchedFromPid */, 0, null, intent, null,
aInfo /*aInfo*/, new Configuration(), null /* resultTo */, null /* resultWho */,
0 /* reqCode */, false /*componentSpecified*/, false /* rootVoiceInteraction */,
- mService.mStackSupervisor, null /* options */, null /* sourceRecord */);
+ mService.mStackSupervisor, options, null /* sourceRecord */);
spyOn(activity);
- activity.mAppWindowToken = mock(AppWindowToken.class);
- doCallRealMethod().when(activity.mAppWindowToken).getOrientationIgnoreVisibility();
- doCallRealMethod().when(activity.mAppWindowToken)
- .setOrientation(anyInt(), any(), any());
- doCallRealMethod().when(activity.mAppWindowToken).setOrientation(anyInt());
- doNothing().when(activity).removeWindowContainer();
- doReturn(mock(Configuration.class)).when(activity.mAppWindowToken)
- .getRequestedOverrideConfiguration();
-
if (mTaskRecord != null) {
- mTaskRecord.addActivityToTop(activity);
+ // fullscreen value is normally read from resources in ctor, so for testing we need
+ // to set it somewhere else since we can't mock resources.
+ activity.fullscreen = true;
+ activity.setTask(mTaskRecord);
+ activity.createAppWindowToken();
+ spyOn(activity.mAppWindowToken);
+ // Make visible by default...
+ activity.mAppWindowToken.setHidden(false);
}
final WindowProcessController wpc = new WindowProcessController(mService,
@@ -305,6 +269,9 @@
mock(WindowProcessListener.class));
wpc.setThread(mock(IApplicationThread.class));
activity.setProcess(wpc);
+
+ // Resume top activities to make sure all other signals in the system are connected.
+ mService.mRootActivityContainer.resumeFocusedStacksTopActivities();
return activity;
}
}
@@ -313,16 +280,13 @@
* Builder for creating new tasks.
*/
protected static class TaskBuilder {
- // Default package name
- static final String DEFAULT_PACKAGE = "com.bar";
-
private final ActivityStackSupervisor mSupervisor;
private ComponentName mComponent;
private String mPackage;
private int mFlags = 0;
// Task id 0 is reserved in ARC for the home app.
- private int mTaskId = 1;
+ private int mTaskId = SystemServicesTestRule.sNextTaskId++;
private int mUserId = 0;
private IVoiceInteractionSession mVoiceSession;
private boolean mCreateStack = true;
@@ -381,6 +345,7 @@
if (mStack == null && mCreateStack) {
mStack = mSupervisor.mRootActivityContainer.getDefaultDisplay().createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ spyOn(mStack);
}
final ActivityInfo aInfo = new ActivityInfo();
@@ -396,450 +361,22 @@
intent.setComponent(mComponent);
intent.setFlags(mFlags);
- final TestTaskRecord task = new TestTaskRecord(mSupervisor.mService, mTaskId, aInfo,
+ final TaskRecord task = new TaskRecord(mSupervisor.mService, mTaskId, aInfo,
intent /*intent*/, mVoiceSession, null /*_voiceInteractor*/);
+ spyOn(task);
task.userId = mUserId;
if (mStack != null) {
mStack.moveToFront("test");
mStack.addTask(task, true, "creating test task");
- task.setStack(mStack);
- task.setTask();
- mStack.getTaskStack().addChild(task.mTask, 0);
+ task.createTask(true, true);
+ spyOn(task.mTask);
}
task.touchActiveTime();
return task;
}
-
- private static class TestTaskRecord extends TaskRecord {
- TestTaskRecord(ActivityTaskManagerService service, int taskId, ActivityInfo info,
- Intent intent, IVoiceInteractionSession voiceSession,
- IVoiceInteractor voiceInteractor) {
- super(service, taskId, info, intent, voiceSession, voiceInteractor);
- }
-
- @Override
- void createTask(boolean onTop, boolean showForAllUsers) {
- setTask();
- }
-
- void setTask() {
- Task mockTask = mock(Task.class);
- mockTask.mTaskRecord = this;
- doCallRealMethod().when(mockTask).onDescendantOrientationChanged(any(), any());
- setTask(mock(Task.class));
- }
- }
- }
-
- protected class TestActivityTaskManagerService extends ActivityTaskManagerService {
- private PackageManagerInternal mPmInternal;
- private PermissionPolicyInternal mPermissionPolicyInternal;
-
- // ActivityStackSupervisor may be created more than once while setting up AMS and ATMS.
- // We keep the reference in order to prevent creating it twice.
- ActivityStackSupervisor mTestStackSupervisor;
-
- ActivityDisplay mDefaultDisplay;
- AppOpsService mAppOpsService;
-
- TestActivityTaskManagerService(Context context) {
- super(context);
- spyOn(this);
-
- mUgmInternal = mock(UriGrantsManagerInternal.class);
- mAppOpsService = mock(AppOpsService.class);
-
- // Make sure permission checks aren't overridden.
- doReturn(AppOpsManager.MODE_DEFAULT)
- .when(mAppOpsService).noteOperation(anyInt(), anyInt(), anyString());
-
- mSupportsMultiWindow = true;
- mSupportsMultiDisplay = true;
- mSupportsSplitScreenMultiWindow = true;
- mSupportsFreeformWindowManagement = true;
- mSupportsPictureInPicture = true;
-
- final TestActivityManagerService am =
- new TestActivityManagerService(mTestInjector, this);
-
- spyOn(getLifecycleManager());
- spyOn(getLockTaskController());
- spyOn(getTaskChangeNotificationController());
- doReturn(mock(IPackageManager.class)).when(this).getPackageManager();
- // allow background activity starts by default
- doReturn(true).when(this).isBackgroundActivityStartsEnabled();
- doNothing().when(this).updateCpuStats();
- }
-
- void setup(IntentFirewall intentFirewall, PendingIntentController intentController,
- ActivityManagerInternal amInternal, WindowManagerService wm, Looper looper) {
- mAmInternal = amInternal;
- initialize(intentFirewall, intentController, looper);
- initRootActivityContainerMocks(wm);
- setWindowManager(wm);
- createDefaultDisplay();
- }
-
- void initRootActivityContainerMocks(WindowManagerService wm) {
- spyOn(mRootActivityContainer);
- mRootActivityContainer.setWindowContainer(mock(RootWindowContainer.class));
- mRootActivityContainer.mWindowManager = wm;
- mRootActivityContainer.mDisplayManager =
- (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
- doNothing().when(mRootActivityContainer).setWindowManager(any());
- // Invoked during {@link ActivityStack} creation.
- doNothing().when(mRootActivityContainer).updateUIDsPresentOnDisplay();
- // Always keep things awake.
- doReturn(true).when(mRootActivityContainer).hasAwakeDisplay();
- // Called when moving activity to pinned stack.
- doNothing().when(mRootActivityContainer).ensureActivitiesVisible(any(), anyInt(),
- anyBoolean());
- }
-
- void createDefaultDisplay() {
- // Create a default display and put a home stack on it so that we'll always have
- // something focusable.
- mDefaultDisplay = TestActivityDisplay.create(mStackSupervisor, DEFAULT_DISPLAY);
- spyOn(mDefaultDisplay);
- mRootActivityContainer.addChild(mDefaultDisplay, ActivityDisplay.POSITION_TOP);
- mDefaultDisplay.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
- final TaskRecord task = new TaskBuilder(mStackSupervisor)
- .setStack(mDefaultDisplay.getHomeStack()).build();
- new ActivityBuilder(this).setTask(task).build();
-
- doReturn(mDefaultDisplay).when(mRootActivityContainer).getDefaultDisplay();
- }
-
- @Override
- int handleIncomingUser(int callingPid, int callingUid, int userId, String name) {
- return userId;
- }
-
- @Override
- AppOpsService getAppOpsService() {
- return mAppOpsService;
- }
-
- @Override
- void updateCpuStats() {
- }
-
- @Override
- void updateBatteryStats(ActivityRecord component, boolean resumed) {
- }
-
- @Override
- void updateActivityUsageStats(ActivityRecord activity, int event) {
- }
-
- @Override
- protected ActivityStackSupervisor createStackSupervisor() {
- if (mTestStackSupervisor == null) {
- mTestStackSupervisor = new TestActivityStackSupervisor(this, mH.getLooper());
- }
- return mTestStackSupervisor;
- }
-
- @Override
- PackageManagerInternal getPackageManagerInternalLocked() {
- if (mPmInternal == null) {
- mPmInternal = mock(PackageManagerInternal.class);
- doReturn(false)
- .when(mPmInternal)
- .isPermissionsReviewRequired(anyString(), anyInt());
- }
- return mPmInternal;
- }
-
- @Override
- PermissionPolicyInternal getPermissionPolicyInternal() {
- if (mPermissionPolicyInternal == null) {
- mPermissionPolicyInternal = mock(PermissionPolicyInternal.class);
- doReturn(true).when(mPermissionPolicyInternal).checkStartActivity(any(), anyInt(),
- any());
- }
- return mPermissionPolicyInternal;
- }
- }
-
- private static class TestInjector extends ActivityManagerService.Injector {
- private ServiceThread mHandlerThread;
-
- TestInjector(Context context) {
- super(context);
- }
-
- @Override
- public AppOpsService getAppOpsService(File file, Handler handler) {
- return null;
- }
-
- @Override
- public Handler getUiHandler(ActivityManagerService service) {
- return mHandlerThread.getThreadHandler();
- }
-
- @Override
- public boolean isNetworkRestrictedForUid(int uid) {
- return false;
- }
-
- void setUp() {
- mHandlerThread = new ServiceThread("ActivityTestsThread",
- Process.THREAD_PRIORITY_DEFAULT, true /* allowIo */);
- mHandlerThread.start();
- }
-
- void tearDown() {
- // Make sure there are no running messages and then quit the thread so the next test
- // won't be affected.
- mHandlerThread.getThreadHandler().runWithScissors(mHandlerThread::quit,
- 0 /* timeout */);
- }
- }
-
- // TODO: Replace this with a mock object since we are no longer in AMS package.
- /**
- * An {@link ActivityManagerService} subclass which provides a test
- * {@link ActivityStackSupervisor}.
- */
- class TestActivityManagerService extends ActivityManagerService {
-
- TestActivityManagerService(TestInjector testInjector, TestActivityTaskManagerService atm) {
- super(testInjector, testInjector.mHandlerThread);
- spyOn(this);
-
- mWindowManager = prepareMockWindowManager();
- mUgmInternal = mock(UriGrantsManagerInternal.class);
-
- atm.setup(mIntentFirewall, mPendingIntentController, new LocalService(), mWindowManager,
- testInjector.mHandlerThread.getLooper());
-
- mActivityTaskManager = atm;
- mAtmInternal = atm.mInternal;
-
- doReturn(mock(IPackageManager.class)).when(this).getPackageManager();
- PackageManagerInternal mockPackageManager = mock(PackageManagerInternal.class);
- doReturn(mockPackageManager).when(this).getPackageManagerInternalLocked();
- doReturn(null).when(mockPackageManager).getDefaultHomeActivity(anyInt());
- doNothing().when(this).grantEphemeralAccessLocked(anyInt(), any(), anyInt(), anyInt());
- }
- }
-
- /**
- * An {@link ActivityStackSupervisor} which stubs out certain methods that depend on
- * setup not available in the test environment. Also specifies an injector for
- */
- protected class TestActivityStackSupervisor extends ActivityStackSupervisor {
- private KeyguardController mKeyguardController;
-
- TestActivityStackSupervisor(ActivityTaskManagerService service, Looper looper) {
- super(service, looper);
- spyOn(this);
- mWindowManager = prepareMockWindowManager();
- mKeyguardController = mock(KeyguardController.class);
-
- // Do not schedule idle that may touch methods outside the scope of the test.
- doNothing().when(this).scheduleIdleLocked();
- doNothing().when(this).scheduleIdleTimeoutLocked(any());
- // unit test version does not handle launch wake lock
- doNothing().when(this).acquireLaunchWakelock();
- doReturn(mKeyguardController).when(this).getKeyguardController();
-
- mLaunchingActivityWakeLock = mock(PowerManager.WakeLock.class);
-
- initialize();
- }
-
- @Override
- public KeyguardController getKeyguardController() {
- return mKeyguardController;
- }
-
- @Override
- void setWindowManager(WindowManagerService wm) {
- mWindowManager = wm;
- }
- }
-
- protected static class TestActivityDisplay extends ActivityDisplay {
- private final ActivityStackSupervisor mSupervisor;
-
- static TestActivityDisplay create(ActivityStackSupervisor supervisor, int displayId) {
- return create(supervisor, displayId, new DisplayInfo());
- }
-
- static TestActivityDisplay create(ActivityStackSupervisor supervisor, int displayId,
- DisplayInfo info) {
- if (displayId == DEFAULT_DISPLAY) {
- return new TestActivityDisplay(supervisor,
- supervisor.mRootActivityContainer.mDisplayManager.getDisplay(displayId));
- }
- final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId,
- info, DEFAULT_DISPLAY_ADJUSTMENTS);
- return new TestActivityDisplay(supervisor, display);
- }
-
- TestActivityDisplay(ActivityStackSupervisor supervisor, Display display) {
- super(supervisor.mService.mRootActivityContainer, display);
- // Normally this comes from display-properties as exposed by WM. Without that, just
- // hard-code to FULLSCREEN for tests.
- setWindowingMode(WINDOWING_MODE_FULLSCREEN);
- mSupervisor = supervisor;
- }
-
- @SuppressWarnings("TypeParameterUnusedInFormals")
- @Override
- ActivityStack createStackUnchecked(int windowingMode, int activityType,
- int stackId, boolean onTop) {
- return new StackBuilder(mSupervisor.mRootActivityContainer).setDisplay(this)
- .setWindowingMode(windowingMode).setActivityType(activityType)
- .setStackId(stackId).setOnTop(onTop).setCreateActivity(false).build();
- }
-
- @Override
- protected DisplayContent createDisplayContent() {
- final DisplayContent displayContent = mock(DisplayContent.class);
- DockedStackDividerController divider = mock(DockedStackDividerController.class);
- doReturn(divider).when(displayContent).getDockedDividerController();
- return displayContent;
- }
-
- void removeAllTasks() {
- for (int i = 0; i < getChildCount(); i++) {
- final ActivityStack stack = getChildAt(i);
- for (TaskRecord task : (List<TaskRecord>) stack.getAllTasks()) {
- stack.removeTask(task, "removeAllTasks", REMOVE_TASK_MODE_DESTROYING);
- }
- }
- }
- }
-
- private static WindowManagerService sMockWindowManagerService;
-
- private static WindowManagerService prepareMockWindowManager() {
- if (sMockWindowManagerService == null) {
- sMockWindowManagerService = mock(WindowManagerService.class);
- }
-
- sMockWindowManagerService.mRoot = mock(RootWindowContainer.class);
-
- doAnswer((InvocationOnMock invocationOnMock) -> {
- final Runnable runnable = invocationOnMock.<Runnable>getArgument(0);
- if (runnable != null) {
- runnable.run();
- }
- return null;
- }).when(sMockWindowManagerService).inSurfaceTransaction(any());
-
- return sMockWindowManagerService;
- }
-
- /**
- * Overridden {@link ActivityStack} that tracks test metrics, such as the number of times a
- * method is called. Note that its functionality depends on the implementations of the
- * construction arguments.
- */
- protected static class TestActivityStack
- extends ActivityStack {
- private int mOnActivityRemovedFromStackCount = 0;
-
- static final int IS_TRANSLUCENT_UNSET = 0;
- static final int IS_TRANSLUCENT_FALSE = 1;
- static final int IS_TRANSLUCENT_TRUE = 2;
- private int mIsTranslucent = IS_TRANSLUCENT_UNSET;
-
- static final int SUPPORTS_SPLIT_SCREEN_UNSET = 0;
- static final int SUPPORTS_SPLIT_SCREEN_FALSE = 1;
- static final int SUPPORTS_SPLIT_SCREEN_TRUE = 2;
- private int mSupportsSplitScreen = SUPPORTS_SPLIT_SCREEN_UNSET;
-
- TestActivityStack(ActivityDisplay display, int stackId, ActivityStackSupervisor supervisor,
- int windowingMode, int activityType, boolean onTop, boolean createActivity) {
- super(display, stackId, supervisor, windowingMode, activityType, onTop);
- if (createActivity) {
- new ActivityBuilder(mService).setCreateTask(true).setStack(this).build();
- if (onTop) {
- // We move the task to front again in order to regain focus after activity
- // added to the stack. Or {@link ActivityDisplay#mPreferredTopFocusableStack}
- // could be other stacks (e.g. home stack).
- moveToFront("createActivityStack");
- } else {
- moveToBack("createActivityStack", null);
- }
- }
- }
-
- @Override
- void onActivityRemovedFromStack(ActivityRecord r) {
- mOnActivityRemovedFromStackCount++;
- super.onActivityRemovedFromStack(r);
- }
-
- // Returns the number of times {@link #onActivityRemovedFromStack} has been called
- int onActivityRemovedFromStackInvocationCount() {
- return mOnActivityRemovedFromStackCount;
- }
-
- @Override
- protected void createTaskStack(int displayId, boolean onTop, Rect outBounds) {
- mTaskStack = mock(TaskStack.class);
-
- // Primary pinned stacks require a non-empty out bounds to be set or else all tasks
- // will be moved to the full screen stack.
- if (getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
- outBounds.set(0, 0, 100, 100);
- }
- }
-
- @Override
- TaskStack getTaskStack() {
- return mTaskStack;
- }
-
- void setIsTranslucent(boolean isTranslucent) {
- mIsTranslucent = isTranslucent ? IS_TRANSLUCENT_TRUE : IS_TRANSLUCENT_FALSE;
- }
-
- @Override
- boolean isStackTranslucent(ActivityRecord starting) {
- switch (mIsTranslucent) {
- case IS_TRANSLUCENT_TRUE:
- return true;
- case IS_TRANSLUCENT_FALSE:
- return false;
- case IS_TRANSLUCENT_UNSET:
- default:
- return super.isStackTranslucent(starting);
- }
- }
-
- void setSupportsSplitScreen(boolean supportsSplitScreen) {
- mSupportsSplitScreen = supportsSplitScreen
- ? SUPPORTS_SPLIT_SCREEN_TRUE : SUPPORTS_SPLIT_SCREEN_FALSE;
- }
-
- @Override
- public boolean supportsSplitScreenWindowingMode() {
- switch (mSupportsSplitScreen) {
- case SUPPORTS_SPLIT_SCREEN_TRUE:
- return true;
- case SUPPORTS_SPLIT_SCREEN_FALSE:
- return false;
- case SUPPORTS_SPLIT_SCREEN_UNSET:
- default:
- return super.supportsSplitScreenWindowingMode();
- }
- }
-
- @Override
- void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity,
- boolean newTask, boolean keepCurTransition,
- ActivityOptions options) {
- }
}
static class StackBuilder {
@@ -886,27 +423,45 @@
return this;
}
- @SuppressWarnings("TypeParameterUnusedInFormals")
ActivityStack build() {
final int stackId = mStackId >= 0 ? mStackId : mDisplay.getNextStackId();
+ final ActivityStack stack;
+ final ActivityStackSupervisor supervisor = mRootActivityContainer.mStackSupervisor;
if (mWindowingMode == WINDOWING_MODE_PINNED) {
- return new ActivityStack(mDisplay, stackId, mRootActivityContainer.mStackSupervisor,
+ stack = new ActivityStack(mDisplay, stackId, supervisor,
mWindowingMode, ACTIVITY_TYPE_STANDARD, mOnTop) {
@Override
Rect getDefaultPictureInPictureBounds(float aspectRatio) {
return new Rect(50, 50, 100, 100);
}
-
- @Override
- void createTaskStack(int displayId, boolean onTop, Rect outBounds) {
- mTaskStack = mock(TaskStack.class);
- }
};
} else {
- return new TestActivityStack(mDisplay, stackId,
- mRootActivityContainer.mStackSupervisor, mWindowingMode,
- mActivityType, mOnTop, mCreateActivity);
+ stack = new ActivityStack(mDisplay, stackId, supervisor,
+ mWindowingMode, mActivityType, mOnTop);
+
+ if (mCreateActivity) {
+ new ActivityBuilder(supervisor.mService)
+ .setCreateTask(true)
+ .setStack(stack)
+ .build();
+ if (mOnTop) {
+ // We move the task to front again in order to regain focus after activity
+ // added to the stack.
+ // Or {@link ActivityDisplay#mPreferredTopFocusableStack} could be other
+ // stacks (e.g. home stack).
+ stack.moveToFront("createActivityStack");
+ } else {
+ stack.moveToBack("createActivityStack", null);
+ }
+ }
}
+
+ spyOn(stack);
+ spyOn(stack.mTaskStack);
+ doNothing().when(stack).startActivityLocked(
+ any(), any(), anyBoolean(), anyBoolean(), any());
+
+ return stack;
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
index 20379a2..e71c8f4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -60,7 +60,7 @@
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
final AppWindowToken translucentOpening = createAppWindowToken(mDisplayContent,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
- translucentOpening.setFillsParent(false);
+ translucentOpening.setOccludesParent(false);
translucentOpening.setHidden(true);
mDisplayContent.mOpeningApps.add(behind);
mDisplayContent.mOpeningApps.add(translucentOpening);
@@ -78,7 +78,7 @@
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
final AppWindowToken translucentClosing = createAppWindowToken(mDisplayContent,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
- translucentClosing.setFillsParent(false);
+ translucentClosing.setOccludesParent(false);
mDisplayContent.mClosingApps.add(translucentClosing);
assertEquals(WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE,
mAppTransitionController.maybeUpdateTransitToTranslucentAnim(
@@ -94,7 +94,7 @@
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
final AppWindowToken translucentOpening = createAppWindowToken(mDisplayContent,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
- translucentOpening.setFillsParent(false);
+ translucentOpening.setOccludesParent(false);
translucentOpening.setHidden(true);
mDisplayContent.mOpeningApps.add(behind);
mDisplayContent.mOpeningApps.add(translucentOpening);
@@ -110,10 +110,10 @@
synchronized (mWm.mGlobalLock) {
final AppWindowToken opening = createAppWindowToken(mDisplayContent,
WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD);
- opening.setFillsParent(false);
+ opening.setOccludesParent(false);
final AppWindowToken closing = createAppWindowToken(mDisplayContent,
WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD);
- closing.setFillsParent(false);
+ closing.setOccludesParent(false);
Task task = opening.getTask();
mDisplayContent.mOpeningApps.add(opening);
mDisplayContent.mClosingApps.add(closing);
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
index d1dc382..c162b6a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
@@ -30,12 +30,14 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
import android.graphics.Rect;
import android.os.IBinder;
@@ -195,6 +197,7 @@
@Test
public void testCancelRemoteAnimationWhenFreeze() {
final DisplayContent dc = createNewDisplay(Display.STATE_ON);
+ doReturn(false).when(dc).onDescendantOrientationChanged(any(), any());
final WindowState exitingAppWindow = createWindow(null /* parent */, TYPE_BASE_APPLICATION,
dc, "exiting app");
final AppWindowToken exitingAppToken = exitingAppWindow.mAppToken;
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
index d9566a3..e387e18 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -36,7 +36,7 @@
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;
import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM;
import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE;
@@ -152,10 +152,6 @@
@Test
@FlakyTest(bugId = 131005232)
public void testLandscapeSeascapeRotationByApp() {
- // Some plumbing to get the service ready for rotation updates.
- mWm.mDisplayReady = true;
- mWm.mDisplayEnabled = true;
-
final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(
TYPE_BASE_APPLICATION);
attrs.setTitle("AppWindow");
@@ -185,25 +181,21 @@
@Test
public void testLandscapeSeascapeRotationByPolicy() {
- // Some plumbing to get the service ready for rotation updates.
- mWm.mDisplayReady = true;
- mWm.mDisplayEnabled = true;
-
- final DisplayRotation spiedRotation = spy(mDisplayContent.getDisplayRotation());
- mDisplayContent.setDisplayRotation(spiedRotation);
+ final DisplayRotation displayRotation = mDisplayContent.getDisplayRotation();
+ spyOn(displayRotation);
final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(
TYPE_BASE_APPLICATION);
- attrs.setTitle("AppWindow");
+ attrs.setTitle("RotationByPolicy");
final WindowTestUtils.TestWindowState appWindow = createWindowState(attrs, mToken);
mToken.addWindow(appWindow);
// Set initial orientation and update.
- performRotation(spiedRotation, Surface.ROTATION_90);
+ performRotation(displayRotation, Surface.ROTATION_90);
appWindow.mResizeReported = false;
// Update the rotation to perform 180 degree rotation and check that resize was reported.
- performRotation(spiedRotation, Surface.ROTATION_270);
+ performRotation(displayRotation, Surface.ROTATION_270);
assertTrue(appWindow.mResizeReported);
appWindow.removeImmediately();
@@ -211,14 +203,7 @@
private void performRotation(DisplayRotation spiedRotation, int rotationToReport) {
doReturn(rotationToReport).when(spiedRotation).rotationForOrientation(anyInt(), anyInt());
- int oldRotation = mDisplayContent.getRotation();
mWm.updateRotation(false, false);
- // Must manually apply here since ATM doesn't know about the display during this test
- // (meaning it can't perform the normal sendNewConfiguration flow).
- mDisplayContent.applyRotationLocked(oldRotation, mDisplayContent.getRotation());
- // Prevent the next rotation from being deferred by animation.
- mWm.mAnimator.setScreenRotationAnimationLocked(mDisplayContent.getDisplayId(), null);
- mWm.mRoot.performSurfacePlacement(false /* recoveringMemory */);
}
@Test
@@ -266,14 +251,14 @@
public void testGetOrientation() {
mToken.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
- mToken.setFillsParent(false);
- // Can specify orientation if app doesn't fill parent.
+ mToken.setOccludesParent(false);
+ // Can specify orientation if app doesn't occludes parent.
assertEquals(SCREEN_ORIENTATION_LANDSCAPE, mToken.getOrientation());
- mToken.setFillsParent(true);
+ mToken.setOccludesParent(true);
mToken.setHidden(true);
mToken.sendingToBottom = true;
- // Can not specify orientation if app isn't visible even though it fills parent.
+ // Can not specify orientation if app isn't visible even though it occludes parent.
assertEquals(SCREEN_ORIENTATION_UNSET, mToken.getOrientation());
// Can specify orientation if the current orientation candidate is orientation behind.
assertEquals(SCREEN_ORIENTATION_LANDSCAPE,
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 388658d..6289768 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -83,7 +83,6 @@
import androidx.test.filters.SmallTest;
-import com.android.dx.mockito.inline.extended.ExtendedMockito;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
import com.android.server.wm.utils.WmDisplayCutout;
@@ -653,25 +652,27 @@
@Test
public void testOnDescendantOrientationRequestChanged() {
final DisplayContent dc = createNewDisplay();
- mWm.mAtmService.mRootActivityContainer = mock(RootActivityContainer.class);
+ dc.getDisplayRotation().setFixedToUserRotation(
+ DisplayRotation.FIXED_TO_USER_ROTATION_DISABLED);
final int newOrientation = dc.getLastOrientation() == SCREEN_ORIENTATION_LANDSCAPE
? SCREEN_ORIENTATION_PORTRAIT
: SCREEN_ORIENTATION_LANDSCAPE;
- final WindowState window = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
- window.getTask().mTaskRecord = mock(TaskRecord.class, ExtendedMockito.RETURNS_DEEP_STUBS);
- window.mAppToken.setOrientation(newOrientation);
+ final ActivityStack stack =
+ new ActivityTestsBase.StackBuilder(mWm.mAtmService.mRootActivityContainer)
+ .setDisplay(dc.mAcitvityDisplay).build();
+ final ActivityRecord activity = stack.topTask().getTopActivity();
- ActivityRecord activityRecord = mock(ActivityRecord.class);
-
- assertTrue("Display should rotate to handle orientation request by default.",
- dc.onDescendantOrientationChanged(window.mToken.token, activityRecord));
+ activity.setRequestedOrientation(newOrientation);
final ArgumentCaptor<Configuration> captor = ArgumentCaptor.forClass(Configuration.class);
verify(dc.mAcitvityDisplay).updateDisplayOverrideConfigurationLocked(captor.capture(),
- same(activityRecord), anyBoolean(), same(null));
+ same(activity), anyBoolean(), same(null));
final Configuration newDisplayConfig = captor.getValue();
- assertEquals(Configuration.ORIENTATION_PORTRAIT, newDisplayConfig.orientation);
+ final int expectedOrientation = newOrientation == SCREEN_ORIENTATION_PORTRAIT
+ ? Configuration.ORIENTATION_PORTRAIT
+ : Configuration.ORIENTATION_LANDSCAPE;
+ assertEquals(expectedOrientation, newDisplayConfig.orientation);
}
@Test
@@ -679,22 +680,20 @@
final DisplayContent dc = createNewDisplay();
dc.getDisplayRotation().setFixedToUserRotation(
DisplayRotation.FIXED_TO_USER_ROTATION_ENABLED);
- mWm.mAtmService.mRootActivityContainer = mock(RootActivityContainer.class);
final int newOrientation = dc.getLastOrientation() == SCREEN_ORIENTATION_LANDSCAPE
? SCREEN_ORIENTATION_PORTRAIT
: SCREEN_ORIENTATION_LANDSCAPE;
- final WindowState window = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
- window.getTask().mTaskRecord = mock(TaskRecord.class, ExtendedMockito.RETURNS_DEEP_STUBS);
- window.mAppToken.setOrientation(newOrientation);
+ final ActivityStack stack =
+ new ActivityTestsBase.StackBuilder(mWm.mAtmService.mRootActivityContainer)
+ .setDisplay(dc.mAcitvityDisplay).build();
+ final ActivityRecord activity = stack.topTask().getTopActivity();
- ActivityRecord activityRecord = mock(ActivityRecord.class);
+ activity.setRequestedOrientation(newOrientation);
- assertFalse("Display shouldn't rotate to handle orientation request if fixed to"
- + " user rotation.",
- dc.onDescendantOrientationChanged(window.mToken.token, activityRecord));
verify(dc.mAcitvityDisplay, never()).updateDisplayOverrideConfigurationLocked(any(),
- eq(activityRecord), anyBoolean(), same(null));
+ eq(activity), anyBoolean(), same(null));
+ assertEquals(dc.getDisplayRotation().getUserRotation(), dc.getRotation());
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
index bfede51..f6f8811 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
@@ -95,7 +95,7 @@
public void setUp() throws Exception {
deleteRecursively(TEST_FOLDER);
- mWm.setSupportsFreeformWindowManagement(false);
+ mWm.mAtmService.mSupportsFreeformWindowManagement = false;
mWm.setIsPc(false);
mWm.setForceDesktopModeOnExternalDisplays(false);
@@ -134,7 +134,7 @@
@Test
public void testPrimaryDisplayDefaultToFullscreen_HasFreeformSupport_NonPc_NoDesktopMode() {
- mWm.setSupportsFreeformWindowManagement(true);
+ mWm.mAtmService.mSupportsFreeformWindowManagement = true;
mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
@@ -144,7 +144,7 @@
@Test
public void testPrimaryDisplayDefaultToFullscreen_HasFreeformSupport_NonPc_HasDesktopMode() {
- mWm.setSupportsFreeformWindowManagement(true);
+ mWm.mAtmService.mSupportsFreeformWindowManagement = true;
mWm.setForceDesktopModeOnExternalDisplays(true);
mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
@@ -155,7 +155,7 @@
@Test
public void testPrimaryDisplayDefaultToFreeform_HasFreeformSupport_IsPc() {
- mWm.setSupportsFreeformWindowManagement(true);
+ mWm.mAtmService.mSupportsFreeformWindowManagement = true;
mWm.setIsPc(true);
mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
@@ -168,7 +168,7 @@
public void testPrimaryDisplayUpdateToFreeform_HasFreeformSupport_IsPc() {
mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
- mWm.setSupportsFreeformWindowManagement(true);
+ mWm.mAtmService.mSupportsFreeformWindowManagement = true;
mWm.setIsPc(true);
mTarget.updateSettingsForDisplay(mPrimaryDisplay);
@@ -187,7 +187,7 @@
@Test
public void testSecondaryDisplayDefaultToFreeform_HasFreeformSupport_NonPc_NoDesktopMode() {
- mWm.setSupportsFreeformWindowManagement(true);
+ mWm.mAtmService.mSupportsFreeformWindowManagement = true;
mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
@@ -197,7 +197,7 @@
@Test
public void testSecondaryDisplayDefaultToFreeform_HasFreeformSupport_NonPc_HasDesktopMode() {
- mWm.setSupportsFreeformWindowManagement(true);
+ mWm.mAtmService.mSupportsFreeformWindowManagement = true;
mWm.setForceDesktopModeOnExternalDisplays(true);
mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
@@ -208,7 +208,7 @@
@Test
public void testSecondaryDisplayDefaultToFreeform_HasFreeformSupport_IsPc() {
- mWm.setSupportsFreeformWindowManagement(true);
+ mWm.mAtmService.mSupportsFreeformWindowManagement = true;
mWm.setIsPc(true);
mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
index b28ae40..be2ee29 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
@@ -331,7 +331,9 @@
mController.layoutTask(task, null /* windowLayout */);
- assertEquals(expected, task.getBounds());
+ // TaskRecord will make adjustments to requested bounds. We only need to guarantee that the
+ // reuqested bounds are expected.
+ assertEquals(expected, task.getRequestedOverrideBounds());
}
/**
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
index e4d3770..49d778f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
@@ -104,6 +104,7 @@
mDisplayUniqueId = "test:" + Integer.toString(sNextUniqueId++);
final DisplayInfo info = new DisplayInfo();
+ mService.mContext.getDisplay().getDisplayInfo(info);
info.uniqueId = mDisplayUniqueId;
mTestDisplay = createNewActivityDisplay(info);
mRootActivityContainer.addChild(mTestDisplay, ActivityDisplay.POSITION_TOP);
diff --git a/services/tests/wmtests/src/com/android/server/wm/PinnedStackControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/PinnedStackControllerTest.java
index 63d9fb9..efd468f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/PinnedStackControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/PinnedStackControllerTest.java
@@ -61,7 +61,7 @@
@Test
public void setShelfHeight_shelfVisibilityChangedTriggered() throws RemoteException {
- mWm.mSupportsPictureInPicture = true;
+ mWm.mAtmService.mSupportsPictureInPicture = true;
mWm.registerPinnedStackListener(DEFAULT_DISPLAY, mIPinnedStackListener);
verify(mIPinnedStackListener).onImeVisibilityChanged(false, 0);
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 b7a85d7..fb4e330 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -32,7 +32,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
@@ -53,14 +53,12 @@
import android.app.ActivityTaskManager;
import android.app.WindowConfiguration;
import android.content.ComponentName;
-import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Bundle;
-import android.os.Looper;
import android.os.RemoteException;
import android.os.SystemClock;
import android.platform.test.annotations.Presubmit;
@@ -93,11 +91,8 @@
private static final int TEST_QUIET_USER_ID = 20;
private static final UserInfo DEFAULT_USER_INFO = new UserInfo();
private static final UserInfo QUIET_USER_INFO = new UserInfo();
- private static int sLastTaskId = 1;
- private static int sLastStackId = 1;
private static final int INVALID_STACK_ID = 999;
- private TestActivityTaskManagerService mTestService;
private ActivityDisplay mDisplay;
private ActivityDisplay mOtherDisplay;
private ActivityDisplay mSingleTaskDisplay;
@@ -115,13 +110,29 @@
@Before
public void setUp() throws Exception {
mTaskPersister = new TestTaskPersister(mContext.getFilesDir());
- mTestService = new MyTestActivityTaskManagerService(mContext);
- mRecentTasks = (TestRecentTasks) mTestService.getRecentTasks();
+
+ // Set testing displays
+ mDisplay = mRootActivityContainer.getActivityDisplay(DEFAULT_DISPLAY);
+ mOtherDisplay = createNewActivityDisplay();
+ mSingleTaskDisplay = createNewActivityDisplay();
+ mSingleTaskDisplay.setDisplayToSingleTaskInstance();
+ mRootActivityContainer.addChild(mOtherDisplay, ActivityDisplay.POSITION_TOP);
+ mRootActivityContainer.addChild(mDisplay, ActivityDisplay.POSITION_TOP);
+ mRootActivityContainer.addChild(mSingleTaskDisplay, ActivityDisplay.POSITION_TOP);
+
+ // Set the recent tasks we should use for testing in this class.
+ mRecentTasks = new TestRecentTasks(mService, mTaskPersister);
+ spyOn(mRecentTasks);
+ mService.setRecentTasks(mRecentTasks);
mRecentTasks.loadParametersFromResources(mContext.getResources());
- mRunningTasks = (TestRunningTasks) mTestService.mStackSupervisor.mRunningTasks;
- mHomeStack = mTestService.mRootActivityContainer.getDefaultDisplay().getOrCreateStack(
+
+ // Set the running tasks we should use for testing in this class.
+ mRunningTasks = new TestRunningTasks();
+ mService.mStackSupervisor.setRunningTasks(mRunningTasks);
+
+ mHomeStack = mDisplay.getOrCreateStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
- mStack = mTestService.mRootActivityContainer.getDefaultDisplay().createStack(
+ mStack = mDisplay.createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
mCallbacksRecorder = new CallbacksRecorder();
mRecentTasks.registerCallback(mCallbacksRecorder);
@@ -723,7 +734,7 @@
ActivityStack stack = mTasks.get(2).getStack();
stack.moveToFront("", mTasks.get(2));
- doReturn(stack).when(mTestService.mRootActivityContainer).getTopDisplayFocusedStack();
+ doReturn(stack).when(mService.mRootActivityContainer).getTopDisplayFocusedStack();
// Simulate the reset from the timeout
mRecentTasks.resetFreezeTaskListReorderingOnTimeout();
@@ -742,10 +753,9 @@
public void testBackStackTasks_expectNoTrim() {
mRecentTasks.setParameters(-1 /* min */, 1 /* max */, -1 /* ms */);
- final MyTestActivityStackSupervisor supervisor =
- (MyTestActivityStackSupervisor) mTestService.mStackSupervisor;
final ActivityStack homeStack = mDisplay.getHomeStack();
- final ActivityStack aboveHomeStack = new MyTestActivityStack(mDisplay, supervisor);
+ final ActivityStack aboveHomeStack = mDisplay.createStack(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
// Add a number of tasks (beyond the max) but ensure that nothing is trimmed because all
// the tasks belong in stacks above the home stack
@@ -761,11 +771,11 @@
public void testBehindHomeStackTasks_expectTaskTrimmed() {
mRecentTasks.setParameters(-1 /* min */, 1 /* max */, -1 /* ms */);
- final MyTestActivityStackSupervisor supervisor =
- (MyTestActivityStackSupervisor) mTestService.mStackSupervisor;
- final ActivityStack behindHomeStack = new MyTestActivityStack(mDisplay, supervisor);
+ final ActivityStack behindHomeStack = mDisplay.createStack(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
final ActivityStack homeStack = mDisplay.getHomeStack();
- final ActivityStack aboveHomeStack = new MyTestActivityStack(mDisplay, supervisor);
+ final ActivityStack aboveHomeStack = mDisplay.createStack(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
// Add a number of tasks (beyond the max) but ensure that only the task in the stack behind
// the home stack is trimmed once a new task is added
@@ -783,10 +793,9 @@
public void testOtherDisplayTasks_expectNoTrim() {
mRecentTasks.setParameters(-1 /* min */, 1 /* max */, -1 /* ms */);
- final MyTestActivityStackSupervisor supervisor =
- (MyTestActivityStackSupervisor) mTestService.mStackSupervisor;
final ActivityStack homeStack = mDisplay.getHomeStack();
- final ActivityStack otherDisplayStack = new MyTestActivityStack(mOtherDisplay, supervisor);
+ final ActivityStack otherDisplayStack = mOtherDisplay.createStack(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
// Add a number of tasks (beyond the max) on each display, ensure that the tasks are not
// removed
@@ -887,16 +896,16 @@
mStack.remove();
// The following APIs should not restore task from recents to the active list.
- assertNotRestoreTask(() -> mTestService.setFocusedTask(taskId));
- assertNotRestoreTask(() -> mTestService.startSystemLockTaskMode(taskId));
- assertNotRestoreTask(() -> mTestService.cancelTaskWindowTransition(taskId));
+ assertNotRestoreTask(() -> mService.setFocusedTask(taskId));
+ assertNotRestoreTask(() -> mService.startSystemLockTaskMode(taskId));
+ assertNotRestoreTask(() -> mService.cancelTaskWindowTransition(taskId));
assertNotRestoreTask(
- () -> mTestService.resizeTask(taskId, null /* bounds */, 0 /* resizeMode */));
+ () -> mService.resizeTask(taskId, null /* bounds */, 0 /* resizeMode */));
assertNotRestoreTask(
- () -> mTestService.setTaskWindowingMode(taskId, WINDOWING_MODE_FULLSCREEN,
+ () -> mService.setTaskWindowingMode(taskId, WINDOWING_MODE_FULLSCREEN,
false/* toTop */));
assertNotRestoreTask(
- () -> mTestService.setTaskWindowingModeSplitScreenPrimary(taskId,
+ () -> mService.setTaskWindowingModeSplitScreenPrimary(taskId,
SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT,
false /* toTop */, false /* animate */, null /* initialBounds */,
true /* showRecents */));
@@ -910,7 +919,7 @@
mRecentTasks.remove(task);
TaskChangeNotificationController controller =
- mTestService.getTaskChangeNotificationController();
+ mService.getTaskChangeNotificationController();
verify(controller, times(2)).notifyTaskListUpdated();
}
@@ -923,7 +932,7 @@
// 2 calls - Once for add and once for remove
TaskChangeNotificationController controller =
- mTestService.getTaskChangeNotificationController();
+ mService.getTaskChangeNotificationController();
verify(controller, times(2)).notifyTaskListUpdated();
}
@@ -938,7 +947,7 @@
// 4 calls - Twice for add and twice for remove
TaskChangeNotificationController controller =
- mTestService.getTaskChangeNotificationController();
+ mService.getTaskChangeNotificationController();
verify(controller, times(4)).notifyTaskListUpdated();
}
@@ -980,7 +989,7 @@
@Test
public void testNotRecentsComponent_denyApiAccess() throws Exception {
- doReturn(PackageManager.PERMISSION_DENIED).when(mTestService)
+ doReturn(PackageManager.PERMISSION_DENIED).when(mService)
.checkGetTasksPermission(anyString(), anyInt(), anyInt());
// Expect the following methods to fail due to recents component not being set
mRecentTasks.setIsCallerRecentsOverride(TestRecentTasks.DENY_THROW_SECURITY_EXCEPTION);
@@ -992,7 +1001,7 @@
@Test
public void testRecentsComponent_allowApiAccessWithoutPermissions() {
- doReturn(PackageManager.PERMISSION_DENIED).when(mTestService)
+ doReturn(PackageManager.PERMISSION_DENIED).when(mService)
.checkGetTasksPermission(anyString(), anyInt(), anyInt());
// Set the recents component and ensure that the following calls do not fail
@@ -1002,62 +1011,62 @@
}
private void doTestRecentTasksApis(boolean expectCallable) {
- assertSecurityException(expectCallable, () -> mTestService.removeStack(INVALID_STACK_ID));
+ assertSecurityException(expectCallable, () -> mService.removeStack(INVALID_STACK_ID));
assertSecurityException(expectCallable,
- () -> mTestService.removeStacksInWindowingModes(
+ () -> mService.removeStacksInWindowingModes(
new int[]{WINDOWING_MODE_UNDEFINED}));
assertSecurityException(expectCallable,
- () -> mTestService.removeStacksWithActivityTypes(
+ () -> mService.removeStacksWithActivityTypes(
new int[]{ACTIVITY_TYPE_UNDEFINED}));
- assertSecurityException(expectCallable, () -> mTestService.removeTask(0));
+ assertSecurityException(expectCallable, () -> mService.removeTask(0));
assertSecurityException(expectCallable,
- () -> mTestService.setTaskWindowingMode(0, WINDOWING_MODE_UNDEFINED, true));
+ () -> mService.setTaskWindowingMode(0, WINDOWING_MODE_UNDEFINED, true));
assertSecurityException(expectCallable,
- () -> mTestService.moveTaskToStack(0, INVALID_STACK_ID, true));
+ () -> mService.moveTaskToStack(0, INVALID_STACK_ID, true));
assertSecurityException(expectCallable,
- () -> mTestService.setTaskWindowingModeSplitScreenPrimary(0,
+ () -> mService.setTaskWindowingModeSplitScreenPrimary(0,
SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT, true, true, new Rect(), true));
- assertSecurityException(expectCallable, () -> mTestService.dismissSplitScreenMode(true));
- assertSecurityException(expectCallable, () -> mTestService.dismissPip(true, 0));
+ assertSecurityException(expectCallable, () -> mService.dismissSplitScreenMode(true));
+ assertSecurityException(expectCallable, () -> mService.dismissPip(true, 0));
assertSecurityException(expectCallable,
- () -> mTestService.moveTopActivityToPinnedStack(INVALID_STACK_ID, new Rect()));
+ () -> mService.moveTopActivityToPinnedStack(INVALID_STACK_ID, new Rect()));
assertSecurityException(expectCallable,
- () -> mTestService.resizeStack(INVALID_STACK_ID, new Rect(), true, true, true, 0));
+ () -> mService.resizeStack(INVALID_STACK_ID, new Rect(), true, true, true, 0));
assertSecurityException(expectCallable,
- () -> mTestService.resizeDockedStack(new Rect(), new Rect(), new Rect(), new Rect(),
+ () -> mService.resizeDockedStack(new Rect(), new Rect(), new Rect(), new Rect(),
new Rect()));
assertSecurityException(expectCallable,
- () -> mTestService.resizePinnedStack(new Rect(), new Rect()));
- assertSecurityException(expectCallable, () -> mTestService.getAllStackInfos());
+ () -> mService.resizePinnedStack(new Rect(), new Rect()));
+ assertSecurityException(expectCallable, () -> mService.getAllStackInfos());
assertSecurityException(expectCallable,
- () -> mTestService.getStackInfo(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_UNDEFINED));
+ () -> mService.getStackInfo(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_UNDEFINED));
assertSecurityException(expectCallable, () -> {
try {
- mTestService.getFocusedStackInfo();
+ mService.getFocusedStackInfo();
} catch (RemoteException e) {
// Ignore
}
});
assertSecurityException(expectCallable,
- () -> mTestService.moveTasksToFullscreenStack(INVALID_STACK_ID, true));
+ () -> mService.moveTasksToFullscreenStack(INVALID_STACK_ID, true));
assertSecurityException(expectCallable,
- () -> mTestService.startActivityFromRecents(0, new Bundle()));
- assertSecurityException(expectCallable, () -> mTestService.getTaskSnapshot(0, true));
- assertSecurityException(expectCallable, () -> mTestService.registerTaskStackListener(null));
+ () -> mService.startActivityFromRecents(0, new Bundle()));
+ assertSecurityException(expectCallable, () -> mService.getTaskSnapshot(0, true));
+ assertSecurityException(expectCallable, () -> mService.registerTaskStackListener(null));
assertSecurityException(expectCallable,
- () -> mTestService.unregisterTaskStackListener(null));
- assertSecurityException(expectCallable, () -> mTestService.getTaskDescription(0));
- assertSecurityException(expectCallable, () -> mTestService.cancelTaskWindowTransition(0));
- assertSecurityException(expectCallable, () -> mTestService.startRecentsActivity(null, null,
+ () -> mService.unregisterTaskStackListener(null));
+ assertSecurityException(expectCallable, () -> mService.getTaskDescription(0));
+ assertSecurityException(expectCallable, () -> mService.cancelTaskWindowTransition(0));
+ assertSecurityException(expectCallable, () -> mService.startRecentsActivity(null, null,
null));
- assertSecurityException(expectCallable, () -> mTestService.cancelRecentsAnimation(true));
- assertSecurityException(expectCallable, () -> mTestService.stopAppSwitches());
- assertSecurityException(expectCallable, () -> mTestService.resumeAppSwitches());
+ assertSecurityException(expectCallable, () -> mService.cancelRecentsAnimation(true));
+ assertSecurityException(expectCallable, () -> mService.stopAppSwitches());
+ assertSecurityException(expectCallable, () -> mService.resumeAppSwitches());
}
private void testGetTasksApis(boolean expectCallable) {
- mTestService.getRecentTasks(MAX_VALUE, 0, TEST_USER_0_ID);
- mTestService.getTasks(MAX_VALUE);
+ mService.getRecentTasks(MAX_VALUE, 0, TEST_USER_0_ID);
+ mService.getTasks(MAX_VALUE);
if (expectCallable) {
assertTrue(mRecentTasks.mLastAllowed);
assertTrue(mRunningTasks.mLastAllowed);
@@ -1072,10 +1081,9 @@
}
private TaskBuilder createTaskBuilder(String packageName, String className) {
- return new TaskBuilder(mTestService.mStackSupervisor)
+ return new TaskBuilder(mService.mStackSupervisor)
.setComponent(new ComponentName(packageName, className))
.setStack(mStack)
- .setTaskId(sLastTaskId++)
.setUserId(TEST_USER_0_ID);
}
@@ -1140,68 +1148,6 @@
}
}
- private class MyTestActivityTaskManagerService extends TestActivityTaskManagerService {
- MyTestActivityTaskManagerService(Context context) {
- super(context);
- }
-
- @Override
- protected RecentTasks createRecentTasks() {
- return spy(new TestRecentTasks(this, mTaskPersister));
- }
-
- @Override
- protected ActivityStackSupervisor createStackSupervisor() {
- if (mTestStackSupervisor == null) {
- mTestStackSupervisor = new MyTestActivityStackSupervisor(this, mH.getLooper());
- }
- return mTestStackSupervisor;
- }
-
- @Override
- void createDefaultDisplay() {
- super.createDefaultDisplay();
- mDisplay = mRootActivityContainer.getActivityDisplay(DEFAULT_DISPLAY);
- mOtherDisplay = TestActivityDisplay.create(mTestStackSupervisor, DEFAULT_DISPLAY + 1);
- mSingleTaskDisplay = TestActivityDisplay.create(mTestStackSupervisor,
- DEFAULT_DISPLAY + 2);
- mSingleTaskDisplay.setDisplayToSingleTaskInstance();
- mRootActivityContainer.addChild(mOtherDisplay, ActivityDisplay.POSITION_TOP);
- mRootActivityContainer.addChild(mDisplay, ActivityDisplay.POSITION_TOP);
- mRootActivityContainer.addChild(mSingleTaskDisplay, ActivityDisplay.POSITION_TOP);
- }
- }
-
- private class MyTestActivityStackSupervisor extends TestActivityStackSupervisor {
- MyTestActivityStackSupervisor(ActivityTaskManagerService service, Looper looper) {
- super(service, looper);
- }
-
- @Override
- RunningTasks createRunningTasks() {
- mRunningTasks = new TestRunningTasks();
- return mRunningTasks;
- }
- }
-
- private static class MyTestActivityStack extends TestActivityStack {
- private ActivityDisplay mDisplay = null;
-
- MyTestActivityStack(ActivityDisplay display, ActivityStackSupervisor supervisor) {
- super(display, sLastStackId++, supervisor, WINDOWING_MODE_FULLSCREEN,
- ACTIVITY_TYPE_STANDARD, true /* onTop */, false /* createActivity */);
- mDisplay = display;
- }
-
- @Override
- ActivityDisplay getDisplay() {
- if (mDisplay != null) {
- return mDisplay;
- }
- return super.getDisplay();
- }
- }
-
private static class CallbacksRecorder implements Callbacks {
public final ArrayList<TaskRecord> mAdded = new ArrayList<>();
public final ArrayList<TaskRecord> mTrimmed = new ArrayList<>();
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index f5a1d75..9ca0180 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -30,6 +30,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verifyNoMoreInteractions;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
+import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE;
import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION;
@@ -132,8 +133,14 @@
@Test
public void testIncludedApps_expectTargetAndVisible() {
mWm.setRecentsAnimationController(mController);
- final AppWindowToken homeAppWindow = createAppWindowToken(mDisplayContent,
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
+ final ActivityStack homStack = mDisplayContent.mAcitvityDisplay.getOrCreateStack(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
+ final AppWindowToken homeAppWindow =
+ new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
+ .setStack(homStack)
+ .setCreateTask(true)
+ .build()
+ .mAppWindowToken;
final AppWindowToken appWindow = createAppWindowToken(mDisplayContent,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
final AppWindowToken hiddenAppWindow = createAppWindowToken(mDisplayContent,
@@ -169,7 +176,7 @@
// Simulate the app transition finishing
mController.mAppTransitionListener.onAppTransitionStartingLocked(0, 0, 0, 0);
- verify(mAnimationCallbacks).onAnimationFinished(REORDER_KEEP_IN_PLACE, true, false);
+ verify(mAnimationCallbacks).onAnimationFinished(REORDER_KEEP_IN_PLACE, false);
}
@Test
@@ -201,7 +208,7 @@
spyOn(mController.mRecentScreenshotAnimator.mAnimatable);
mController.mRecentScreenshotAnimator.cancelAnimation();
verify(mController.mRecentScreenshotAnimator.mAnimatable).onAnimationLeashLost(any());
- verify(mAnimationCallbacks).onAnimationFinished(REORDER_KEEP_IN_PLACE, true, false);
+ verify(mAnimationCallbacks).onAnimationFinished(REORDER_KEEP_IN_PLACE, false);
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
index 0e119e3..dcc295c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
@@ -74,8 +74,9 @@
@Before
public void setUp() throws Exception {
mRecentsAnimationController = mock(RecentsAnimationController.class);
- doReturn(mRecentsAnimationController).when(
- mService.mWindowManager).getRecentsAnimationController();
+ mService.mWindowManager.setRecentsAnimationController(mRecentsAnimationController);
+ doNothing().when(mService.mWindowManager).initializeRecentsAnimation(
+ anyInt(), any(), any(), anyInt(), any());
doReturn(true).when(mService.mWindowManager).canStartRecentsAnimation();
final RecentTasks recentTasks = mService.getRecentTasks();
@@ -107,16 +108,25 @@
assertTrue(recentActivity.visible);
// Simulate the animation is cancelled without changing the stack order.
- recentsAnimation.onAnimationFinished(REORDER_KEEP_IN_PLACE, true /* runSychronously */,
- false /* sendUserLeaveHint */);
+ recentsAnimation.onAnimationFinished(REORDER_KEEP_IN_PLACE, false /* sendUserLeaveHint */);
// The non-top recents activity should be invisible by the restored launch-behind state.
assertFalse(recentActivity.visible);
}
@Test
public void testPreloadRecentsActivity() {
- // Ensure that the fake recent component can be resolved by the recents intent.
- mockTaskRecordFactory(builder -> builder.setComponent(mRecentsComponent));
+ final ActivityDisplay defaultDisplay = mRootActivityContainer.getDefaultDisplay();
+ final ActivityStack homeStack =
+ defaultDisplay.getStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
+ defaultDisplay.positionChildAtTop(homeStack, false /* includingParents */);
+ ActivityRecord topRunningHomeActivity = homeStack.topRunningActivityLocked();
+ if (topRunningHomeActivity == null) {
+ topRunningHomeActivity = new ActivityBuilder(mService)
+ .setStack(homeStack)
+ .setCreateTask(true)
+ .build();
+ }
+
ActivityInfo aInfo = new ActivityInfo();
aInfo.applicationInfo = new ApplicationInfo();
aInfo.applicationInfo.uid = 10001;
@@ -204,6 +214,13 @@
ActivityStack homeStack = display.getHomeStack();
// Assume the home activity support recents.
ActivityRecord targetActivity = homeStack.getTopActivity();
+ if (targetActivity == null) {
+ targetActivity = new ActivityBuilder(mService)
+ .setCreateTask(true)
+ .setStack(homeStack)
+ .build();
+ }
+
// Put another home activity in home stack.
ActivityRecord anotherHomeActivity = new ActivityBuilder(mService)
.setComponent(new ComponentName(mContext.getPackageName(), "Home2"))
@@ -226,13 +243,12 @@
anotherHomeActivity.moveFocusableActivityToTop("launchAnotherHome");
// The current top activity is not the recents so the animation should be canceled.
- verify(mService.mWindowManager, times(1)).cancelRecentsAnimationSynchronously(
+ verify(mService.mWindowManager, times(1)).cancelRecentsAnimation(
eq(REORDER_KEEP_IN_PLACE), any() /* reason */);
// The test uses mocked RecentsAnimationController so we have to invoke the callback
// manually to simulate the flow.
- recentsAnimation.onAnimationFinished(REORDER_KEEP_IN_PLACE, true /* runSychronously */,
- false /* sendUserLeaveHint */);
+ recentsAnimation.onAnimationFinished(REORDER_KEEP_IN_PLACE, false /* sendUserLeaveHint */);
// We should restore the launch-behind of the original target activity.
assertFalse(targetActivity.mLaunchTaskBehind);
}
@@ -269,7 +285,7 @@
fullscreenStack.moveToFront("Activity start");
// Ensure that the recents animation was canceled by cancelAnimationSynchronously().
- verify(mService.mWindowManager, times(1)).cancelRecentsAnimationSynchronously(
+ verify(mService.mWindowManager, times(1)).cancelRecentsAnimation(
eq(REORDER_KEEP_IN_PLACE), any());
// Assume recents animation already started, set a state that cancel recents animation
@@ -314,7 +330,7 @@
fullscreenStack.remove();
// Ensure that the recents animation was NOT canceled
- verify(mService.mWindowManager, times(0)).cancelRecentsAnimationSynchronously(
+ verify(mService.mWindowManager, times(0)).cancelRecentsAnimation(
eq(REORDER_KEEP_IN_PLACE), any());
verify(mRecentsAnimationController, times(0)).setCancelOnNextTransitionStart();
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
index d4f24f9..539a79c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -97,7 +97,7 @@
*/
@Test
public void testRestoringInvalidTask() {
- ((TestActivityDisplay) mRootActivityContainer.getDefaultDisplay()).removeAllTasks();
+ mRootActivityContainer.getDefaultDisplay().removeAllTasks();
TaskRecord task = mRootActivityContainer.anyTaskForId(0 /*taskId*/,
MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, null, false /* onTop */);
assertNull(task);
@@ -304,21 +304,23 @@
*/
@Test
public void testResizeDockedStackForSplitScreenPrimary() {
- final Rect taskSize = new Rect(0, 0, 600, 600);
+ final Rect taskSize = new Rect(0, 0, 1000, 1000);
final Rect stackSize = new Rect(0, 0, 300, 300);
// Create primary split-screen stack with a task.
- final ActivityStack primaryStack = mRootActivityContainer.getDefaultDisplay()
- .createStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD,
- true /* onTop */);
- final TaskRecord task = new TaskBuilder(mSupervisor).setStack(primaryStack).build();
+ final ActivityStack primaryStack = new StackBuilder(mRootActivityContainer)
+ .setActivityType(ACTIVITY_TYPE_STANDARD)
+ .setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)
+ .setOnTop(true)
+ .build();
+ final TaskRecord task = primaryStack.topTask();
// Resize dock stack.
mService.resizeDockedStack(stackSize, taskSize, null, null, null);
// Verify dock stack & its task bounds if is equal as resized result.
- assertEquals(primaryStack.getBounds(), stackSize);
- assertEquals(task.getBounds(), taskSize);
+ assertEquals(stackSize, primaryStack.getBounds());
+ assertEquals(taskSize, task.getBounds());
}
/**
@@ -328,8 +330,9 @@
public void testFindTaskToMoveToFrontWhenRecentsOnTop() {
// Create stack/task on default display.
final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
- final TestActivityStack targetStack = (TestActivityStack) new StackBuilder(
- mRootActivityContainer).setOnTop(false).build();
+ final ActivityStack targetStack = new StackBuilder(mRootActivityContainer)
+ .setOnTop(false)
+ .build();
final TaskRecord targetTask = targetStack.getChildAt(0);
// Create Recents on top of the display.
@@ -505,12 +508,10 @@
mockResolveSecondaryHomeActivity();
// Create secondary displays.
- final TestActivityDisplay secondDisplay = spy(createNewActivityDisplay());
+ final TestActivityDisplay secondDisplay = createNewActivityDisplay();
mRootActivityContainer.addChild(secondDisplay, POSITION_TOP);
doReturn(true).when(secondDisplay).supportsSystemDecorations();
- // Create mock tasks and other necessary mocks.
- mockTaskRecordFactory();
doReturn(true).when(mRootActivityContainer)
.ensureVisibilityAndConfig(any(), anyInt(), anyBoolean(), anyBoolean());
doReturn(true).when(mRootActivityContainer).canStartHomeOnDisplay(
@@ -621,7 +622,6 @@
info.applicationInfo.packageName = "android";
info.name = ResolverActivity.class.getName();
doReturn(info).when(mRootActivityContainer).resolveHomeActivity(anyInt(), any());
- mockTaskRecordFactory();
mRootActivityContainer.startHomeOnDisplay(0 /* userId */, "test", DEFAULT_DISPLAY);
final ActivityRecord resolverActivity = mRootActivityContainer.topRunningActivity();
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index f51ce13..db105dd 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -96,7 +96,7 @@
mWm.getDefaultDisplayContentLocked().getWindowingMode());
mWm.mIsPc = true;
- mWm.mSupportsFreeformWindowManagement = true;
+ mWm.mAtmService.mSupportsFreeformWindowManagement = true;
mWm.mRoot.onSettingsRetrieved();
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index df7c9a4..1ad0e00 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -16,6 +16,9 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.os.Process.THREAD_PRIORITY_DEFAULT;
import static android.testing.DexmakerShareClassLoaderRule.runWithDexmakerShareClassLoader;
import static android.view.Display.DEFAULT_DISPLAY;
@@ -25,67 +28,91 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyString;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.nullable;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.app.ActivityManagerInternal;
import android.app.AppOpsManager;
+import android.app.usage.UsageStatsManagerInternal;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.IntentFilter;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManagerInternal;
import android.database.ContentObserver;
+import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerInternal;
import android.net.Uri;
import android.os.Handler;
+import android.os.Looper;
+import android.os.PowerManager;
import android.os.PowerManagerInternal;
import android.os.PowerSaveState;
import android.os.UserHandle;
-import android.view.Display;
+import android.provider.DeviceConfig;
import android.view.InputChannel;
+import android.view.Surface;
+import android.view.SurfaceControl;
import com.android.dx.mockito.inline.extended.StaticMockitoSession;
+import com.android.server.AnimationThread;
+import com.android.server.DisplayThread;
import com.android.server.LocalServices;
import com.android.server.LockGuard;
+import com.android.server.ServiceThread;
import com.android.server.Watchdog;
+import com.android.server.am.ActivityManagerService;
+import com.android.server.appop.AppOpsService;
+import com.android.server.display.color.ColorDisplayService;
import com.android.server.input.InputManagerService;
+import com.android.server.policy.PermissionPolicyInternal;
import com.android.server.policy.WindowManagerPolicy;
-import com.android.server.wm.utils.MockTracker;
+import com.android.server.statusbar.StatusBarManagerInternal;
+import com.android.server.uri.UriGrantsManagerInternal;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
-import org.mockito.invocation.InvocationOnMock;
+import org.mockito.Mockito;
import org.mockito.quality.Strictness;
+import java.io.File;
import java.util.concurrent.atomic.AtomicBoolean;
/**
- * JUnit test rule to create a mock {@link WindowManagerService} instance for tests.
+ * JUnit test rule to correctly setting up system services like {@link WindowManagerService}
+ * and {@link ActivityTaskManagerService} for tests.
*/
public class SystemServicesTestRule implements TestRule {
private static final String TAG = SystemServicesTestRule.class.getSimpleName();
+ static int sNextDisplayId = DEFAULT_DISPLAY + 100;
+ static int sNextTaskId = 100;
+
private final AtomicBoolean mCurrentMessagesProcessed = new AtomicBoolean(false);
- private MockTracker mMockTracker;
+ private Context mContext;
private StaticMockitoSession mMockitoSession;
- private WindowManagerService mWindowManagerService;
- private TestWindowManagerPolicy mWindowManagerPolicy;
-
- /** {@link MockTracker} to track mocks created by {@link SystemServicesTestRule}. */
- private static class Tracker extends MockTracker {
- // This empty extended class is necessary since Mockito distinguishes a listener by it
- // class.
- }
+ ServiceThread mHandlerThread;
+ private ActivityManagerService mAmService;
+ private ActivityTaskManagerService mAtmService;
+ private WindowManagerService mWmService;
+ private TestWindowManagerPolicy mWMPolicy;
+ private WindowState.PowerManagerWrapper mPowerManagerWrapper;
+ private InputManagerService mImService;
+ /**
+ * Spied {@link SurfaceControl.Transaction} class than can be used to verify calls.
+ */
+ SurfaceControl.Transaction mTransaction;
@Override
public Statement apply(Statement base, Description description) {
@@ -103,8 +130,6 @@
}
private void setUp() {
- mMockTracker = new Tracker();
-
mMockitoSession = mockitoSession()
.spyStatic(LocalServices.class)
.mockStatic(LockGuard.class)
@@ -112,101 +137,220 @@
.strictness(Strictness.LENIENT)
.startMocking();
+ setUpSystemCore();
+ setUpLocalServices();
+ setUpActivityTaskManagerService();
+ setUpWindowManagerService();
+ }
+
+ private void setUpSystemCore() {
+ mHandlerThread = new ServiceThread(
+ "WmTestsThread", THREAD_PRIORITY_DEFAULT, true /* allowIo */);
+ mHandlerThread.start();
+
doReturn(mock(Watchdog.class)).when(Watchdog::getInstance);
- final Context context = getInstrumentation().getTargetContext();
- spyOn(context);
+ mContext = getInstrumentation().getTargetContext();
+ spyOn(mContext);
- doReturn(null).when(context)
+ doReturn(null).when(mContext)
.registerReceiver(nullable(BroadcastReceiver.class), any(IntentFilter.class));
- doReturn(null).when(context)
+ doReturn(null).when(mContext)
.registerReceiverAsUser(any(BroadcastReceiver.class), any(UserHandle.class),
any(IntentFilter.class), nullable(String.class), nullable(Handler.class));
- final ContentResolver contentResolver = context.getContentResolver();
+ final ContentResolver contentResolver = mContext.getContentResolver();
spyOn(contentResolver);
doNothing().when(contentResolver)
.registerContentObserver(any(Uri.class), anyBoolean(), any(ContentObserver.class),
anyInt());
+ }
- final AppOpsManager appOpsManager = mock(AppOpsManager.class);
- doReturn(appOpsManager).when(context)
- .getSystemService(eq(Context.APP_OPS_SERVICE));
+ private void setUpLocalServices() {
+ // Tear down any local services just in case.
+ tearDownLocalServices();
+ // UriGrantsManagerInternal
+ final UriGrantsManagerInternal ugmi = mock(UriGrantsManagerInternal.class);
+ LocalServices.addService(UriGrantsManagerInternal.class, ugmi);
+
+ // AppOpsManager
+ final AppOpsManager aom = mock(AppOpsManager.class);
+ doReturn(aom).when(mContext).getSystemService(eq(Context.APP_OPS_SERVICE));
+
+ // DisplayManagerInternal
final DisplayManagerInternal dmi = mock(DisplayManagerInternal.class);
doReturn(dmi).when(() -> LocalServices.getService(eq(DisplayManagerInternal.class)));
+ // ColorDisplayServiceInternal
+ final ColorDisplayService.ColorDisplayServiceInternal cds =
+ mock(ColorDisplayService.ColorDisplayServiceInternal.class);
+ doReturn(cds).when(() -> LocalServices.getService(
+ eq(ColorDisplayService.ColorDisplayServiceInternal.class)));
+
+ final UsageStatsManagerInternal usmi = mock(UsageStatsManagerInternal.class);
+ LocalServices.addService(UsageStatsManagerInternal.class, usmi);
+
+ // PackageManagerInternal
+ final PackageManagerInternal packageManagerInternal = mock(PackageManagerInternal.class);
+ LocalServices.addService(PackageManagerInternal.class, packageManagerInternal);
+ doReturn(false).when(packageManagerInternal).isPermissionsReviewRequired(
+ anyString(), anyInt());
+ doReturn(null).when(packageManagerInternal).getDefaultHomeActivity(anyInt());
+
+ // PowerManagerInternal
final PowerManagerInternal pmi = mock(PowerManagerInternal.class);
final PowerSaveState state = new PowerSaveState.Builder().build();
doReturn(state).when(pmi).getLowPowerState(anyInt());
doReturn(pmi).when(() -> LocalServices.getService(eq(PowerManagerInternal.class)));
- final ActivityManagerInternal ami = mock(ActivityManagerInternal.class);
- doReturn(ami).when(() -> LocalServices.getService(eq(ActivityManagerInternal.class)));
+ // PermissionPolicyInternal
+ final PermissionPolicyInternal ppi = mock(PermissionPolicyInternal.class);
+ LocalServices.addService(PermissionPolicyInternal.class, ppi);
+ doReturn(true).when(ppi).checkStartActivity(any(), anyInt(), any());
- final ActivityTaskManagerInternal atmi = mock(ActivityTaskManagerInternal.class);
- doAnswer((InvocationOnMock invocationOnMock) -> {
- final Runnable runnable = invocationOnMock.getArgument(0);
- if (runnable != null) {
- runnable.run();
- }
- return null;
- }).when(atmi).notifyKeyguardFlagsChanged(nullable(Runnable.class), anyInt());
- doReturn(atmi).when(() -> LocalServices.getService(eq(ActivityTaskManagerInternal.class)));
-
- final InputManagerService ims = mock(InputManagerService.class);
+ // InputManagerService
+ mImService = mock(InputManagerService.class);
// InputChannel is final and can't be mocked.
final InputChannel[] input = InputChannel.openInputChannelPair(TAG_WM);
if (input != null && input.length > 1) {
- doReturn(input[1]).when(ims).monitorInput(anyString(), anyInt());
+ doReturn(input[1]).when(mImService).monitorInput(anyString(), anyInt());
}
- final ActivityTaskManagerService atms = mock(ActivityTaskManagerService.class);
- final TaskChangeNotificationController taskChangeNotificationController = mock(
- TaskChangeNotificationController.class);
- doReturn(taskChangeNotificationController).when(atms).getTaskChangeNotificationController();
- final WindowManagerGlobalLock wmLock = new WindowManagerGlobalLock();
- doReturn(wmLock).when(atms).getGlobalLock();
+ // StatusBarManagerInternal
+ final StatusBarManagerInternal sbmi = mock(StatusBarManagerInternal.class);
+ doReturn(sbmi).when(() -> LocalServices.getService(eq(StatusBarManagerInternal.class)));
+ }
- mWindowManagerPolicy = new TestWindowManagerPolicy(this::getWindowManagerService);
- mWindowManagerService = WindowManagerService.main(
- context, ims, false, false, mWindowManagerPolicy, atms, StubTransaction::new);
+ private void setUpActivityTaskManagerService() {
+ // ActivityManagerService
+ mAmService = new ActivityManagerService(
+ new AMTestInjector(mContext, mHandlerThread), mHandlerThread);
+ spyOn(mAmService);
+ doReturn(mock(IPackageManager.class)).when(mAmService).getPackageManager();
+ doNothing().when(mAmService).grantEphemeralAccessLocked(
+ anyInt(), any(), anyInt(), anyInt());
- mWindowManagerService.onInitReady();
+ // ActivityManagerInternal
+ final ActivityManagerInternal amInternal = mAmService.mInternal;
+ spyOn(amInternal);
+ doNothing().when(amInternal).trimApplications();
+ doNothing().when(amInternal).updateCpuStats();
+ doNothing().when(amInternal).updateOomAdj();
+ doNothing().when(amInternal).updateBatteryStats(any(), anyInt(), anyInt(), anyBoolean());
+ doNothing().when(amInternal).updateActivityUsageStats(
+ any(), anyInt(), anyInt(), any(), any());
+ doNothing().when(amInternal).startProcess(
+ any(), any(), anyBoolean(), anyBoolean(), any(), any());
+ doNothing().when(amInternal).updateOomLevelsForDisplay(anyInt());
+ LocalServices.addService(ActivityManagerInternal.class, amInternal);
- final Display display = mWindowManagerService.mDisplayManager.getDisplay(DEFAULT_DISPLAY);
- // Display creation is driven by the ActivityManagerService via
- // ActivityStackSupervisor. We emulate those steps here.
- DisplayContent displayContent = mWindowManagerService.mRoot
- .createDisplayContent(display, mock(ActivityDisplay.class));
- displayContent.reconfigureDisplayLocked();
+ mAtmService = new TestActivityTaskManagerService(mContext, mAmService);
+ LocalServices.addService(ActivityTaskManagerInternal.class, mAtmService.getAtmInternal());
+ }
- mMockTracker.stopTracking();
+ private void setUpWindowManagerService() {
+ mPowerManagerWrapper = mock(WindowState.PowerManagerWrapper.class);
+ mWMPolicy = new TestWindowManagerPolicy(this::getWindowManagerService,
+ mPowerManagerWrapper);
+ mWmService = WindowManagerService.main(
+ mContext, mImService, false, false, mWMPolicy, mAtmService, StubTransaction::new);
+ spyOn(mWmService);
+
+ // Setup factory classes to prevent calls to native code.
+ mTransaction = spy(StubTransaction.class);
+ // Return a spied Transaction class than can be used to verify calls.
+ mWmService.mTransactionFactory = () -> mTransaction;
+ // Return a SurfaceControl.Builder class that creates mocked SurfaceControl instances.
+ mWmService.mSurfaceBuilderFactory = (unused) -> new MockSurfaceControlBuilder();
+ // Return mocked Surface instances.
+ mWmService.mSurfaceFactory = () -> mock(Surface.class);
+ mWmService.mSurfaceAnimationRunner = new SurfaceAnimationRunner(
+ null, null, mTransaction, mWmService.mPowerManagerInternal);
+
+ mWmService.onInitReady();
+ mAmService.setWindowManager(mWmService);
+ mWmService.mDisplayEnabled = true;
+ mWmService.mDisplayReady = true;
+ // Set configuration for default display
+ mWmService.getDefaultDisplayContentLocked().reconfigureDisplayLocked();
+
+ // Mock root, some default display, and home stack.
+ spyOn(mWmService.mRoot);
+ final ActivityDisplay display = mAtmService.mRootActivityContainer.getDefaultDisplay();
+ spyOn(display);
+ spyOn(display.mDisplayContent);
+ final ActivityStack homeStack = display.getStack(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
+ spyOn(homeStack);
+ spyOn(homeStack.mTaskStack);
}
private void tearDown() {
waitUntilWindowManagerHandlersIdle();
- removeLocalServices();
- mWindowManagerService = null;
- mWindowManagerPolicy = null;
+ // Unregister display listener from root to avoid issues with subsequent tests.
+ mContext.getSystemService(DisplayManager.class)
+ .unregisterDisplayListener(mAtmService.mRootActivityContainer);
+ // ProptertiesChangesListener is registered in the constructor of WindowManagerService to
+ // a static object, so we need to clean it up in tearDown(), even though we didn't set up
+ // in tests.
+ DeviceConfig.removeOnPropertiesChangedListener(mWmService.mPropertiesChangedListener);
+ mWmService = null;
+ mWMPolicy = null;
+ mPowerManagerWrapper = null;
+
+ tearDownLocalServices();
+ tearDownSystemCore();
+
+ // Needs to explicitly dispose current static threads because there could be messages
+ // scheduled at a later time, and all mocks are invalid when it's executed.
+ DisplayThread.dispose();
+ AnimationThread.dispose();
+ // Reset priority booster because animation thread has been changed.
+ WindowManagerService.sThreadPriorityBooster = new WindowManagerThreadPriorityBooster();
+
+ Mockito.framework().clearInlineMocks();
+ }
+
+ private void tearDownSystemCore() {
if (mMockitoSession != null) {
mMockitoSession.finishMocking();
mMockitoSession = null;
}
- if (mMockTracker != null) {
- mMockTracker.close();
- mMockTracker = null;
+ if (mHandlerThread != null) {
+ // Make sure there are no running messages and then quit the thread so the next test
+ // won't be affected.
+ mHandlerThread.getThreadHandler().runWithScissors(mHandlerThread::quit,
+ 0 /* timeout */);
}
}
- private static void removeLocalServices() {
+ private static void tearDownLocalServices() {
+ LocalServices.removeServiceForTest(DisplayManagerInternal.class);
+ LocalServices.removeServiceForTest(PowerManagerInternal.class);
+ LocalServices.removeServiceForTest(ActivityManagerInternal.class);
+ LocalServices.removeServiceForTest(ActivityTaskManagerInternal.class);
LocalServices.removeServiceForTest(WindowManagerInternal.class);
LocalServices.removeServiceForTest(WindowManagerPolicy.class);
+ LocalServices.removeServiceForTest(PackageManagerInternal.class);
+ LocalServices.removeServiceForTest(UriGrantsManagerInternal.class);
+ LocalServices.removeServiceForTest(PermissionPolicyInternal.class);
+ LocalServices.removeServiceForTest(ColorDisplayService.ColorDisplayServiceInternal.class);
+ LocalServices.removeServiceForTest(UsageStatsManagerInternal.class);
+ LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
}
WindowManagerService getWindowManagerService() {
- return mWindowManagerService;
+ return mWmService;
+ }
+
+ ActivityTaskManagerService getActivityTaskManagerService() {
+ return mAtmService;
+ }
+
+ WindowState.PowerManagerWrapper getPowerManagerWrapper() {
+ return mPowerManagerWrapper;
}
void cleanupWindowManagerHandlers() {
@@ -229,6 +373,7 @@
waitHandlerIdle(wm.mH);
waitHandlerIdle(wm.mAnimationHandler);
waitHandlerIdle(SurfaceAnimationThread.getHandler());
+ waitHandlerIdle(mHandlerThread.getThreadHandler());
}
private void waitHandlerIdle(Handler handler) {
@@ -251,4 +396,121 @@
}
}
}
+
+ protected class TestActivityTaskManagerService extends ActivityTaskManagerService {
+ // ActivityStackSupervisor may be created more than once while setting up AMS and ATMS.
+ // We keep the reference in order to prevent creating it twice.
+ ActivityStackSupervisor mTestStackSupervisor;
+
+ TestActivityTaskManagerService(Context context, ActivityManagerService ams) {
+ super(context);
+ spyOn(this);
+
+ mSupportsMultiWindow = true;
+ mSupportsMultiDisplay = true;
+ mSupportsSplitScreenMultiWindow = true;
+ mSupportsFreeformWindowManagement = true;
+ mSupportsPictureInPicture = true;
+
+ doReturn(mock(IPackageManager.class)).when(this).getPackageManager();
+ // allow background activity starts by default
+ doReturn(true).when(this).isBackgroundActivityStartsEnabled();
+ doNothing().when(this).updateCpuStats();
+
+ // AppOpsService
+ final AppOpsService aos = mock(AppOpsService.class);
+ doReturn(aos).when(this).getAppOpsService();
+ // Make sure permission checks aren't overridden.
+ doReturn(AppOpsManager.MODE_DEFAULT)
+ .when(aos).noteOperation(anyInt(), anyInt(), anyString());
+
+ setUsageStatsManager(LocalServices.getService(UsageStatsManagerInternal.class));
+ ams.mActivityTaskManager = this;
+ ams.mAtmInternal = mInternal;
+ onActivityManagerInternalAdded();
+ initialize(
+ ams.mIntentFirewall, ams.mPendingIntentController, mHandlerThread.getLooper());
+ spyOn(getLifecycleManager());
+ spyOn(getLockTaskController());
+ spyOn(getTaskChangeNotificationController());
+ initRootActivityContainerMocks();
+ }
+
+ void initRootActivityContainerMocks() {
+ spyOn(mRootActivityContainer);
+ // Invoked during {@link ActivityStack} creation.
+ doNothing().when(mRootActivityContainer).updateUIDsPresentOnDisplay();
+ // Always keep things awake.
+ doReturn(true).when(mRootActivityContainer).hasAwakeDisplay();
+ // Called when moving activity to pinned stack.
+ doNothing().when(mRootActivityContainer).ensureActivitiesVisible(any(), anyInt(),
+ anyBoolean());
+ }
+
+ @Override
+ int handleIncomingUser(int callingPid, int callingUid, int userId, String name) {
+ return userId;
+ }
+
+ @Override
+ protected ActivityStackSupervisor createStackSupervisor() {
+ if (mTestStackSupervisor == null) {
+ mTestStackSupervisor = new TestActivityStackSupervisor(this, mH.getLooper());
+ }
+ return mTestStackSupervisor;
+ }
+ }
+
+ /**
+ * An {@link ActivityStackSupervisor} which stubs out certain methods that depend on
+ * setup not available in the test environment. Also specifies an injector for
+ */
+ protected class TestActivityStackSupervisor extends ActivityStackSupervisor {
+
+ TestActivityStackSupervisor(ActivityTaskManagerService service, Looper looper) {
+ super(service, looper);
+ spyOn(this);
+
+ // Do not schedule idle that may touch methods outside the scope of the test.
+ doNothing().when(this).scheduleIdleLocked();
+ doNothing().when(this).scheduleIdleTimeoutLocked(any());
+ // unit test version does not handle launch wake lock
+ doNothing().when(this).acquireLaunchWakelock();
+ doReturn(mock(KeyguardController.class)).when(this).getKeyguardController();
+
+ mLaunchingActivityWakeLock = mock(PowerManager.WakeLock.class);
+
+ initialize();
+ }
+ }
+
+ // TODO: Can we just mock this?
+ private static class AMTestInjector extends ActivityManagerService.Injector {
+ private ServiceThread mHandlerThread;
+
+ AMTestInjector(Context context, ServiceThread handlerThread) {
+ super(context);
+ mHandlerThread = handlerThread;
+ }
+
+ @Override
+ public Context getContext() {
+ return getInstrumentation().getTargetContext();
+ }
+
+ @Override
+ public AppOpsService getAppOpsService(File file, Handler handler) {
+ return null;
+ }
+
+ @Override
+ public Handler getUiHandler(ActivityManagerService service) {
+ return mHandlerThread.getThreadHandler();
+ }
+
+ @Override
+ public boolean isNetworkRestrictedForUid(int uid) {
+ return false;
+ }
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
index 2cebebf..bcff704 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
@@ -1277,17 +1277,18 @@
}
private ActivityRecord createSourceActivity(TestActivityDisplay display) {
- final TestActivityStack stack = display.createStack(display.getWindowingMode(),
+ final ActivityStack stack = display.createStack(display.getWindowingMode(),
ACTIVITY_TYPE_STANDARD, true);
return new ActivityBuilder(mService).setStack(stack).setCreateTask(true).build();
}
private void addFreeformTaskTo(TestActivityDisplay display, Rect bounds) {
- final TestActivityStack stack = display.createStack(display.getWindowingMode(),
+ final ActivityStack stack = display.createStack(display.getWindowingMode(),
ACTIVITY_TYPE_STANDARD, true);
stack.setWindowingMode(WINDOWING_MODE_FREEFORM);
final TaskRecord task = new TaskBuilder(mSupervisor).setStack(stack).build();
- task.setBounds(bounds);
+ // Just work around the unnecessary adjustments for bounds.
+ task.getWindowConfiguration().setBounds(bounds);
}
private void assertEquivalentWindowingMode(int expected, int actual, int parentWindowingMode) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index a0302f6..c83401b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -28,14 +28,19 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.util.DisplayMetrics.DENSITY_DEFAULT;
import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_90;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.server.policy.WindowManagerPolicy.USER_ROTATION_FREE;
+import static com.android.server.wm.DisplayRotation.FIXED_TO_USER_ROTATION_ENABLED;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.sameInstance;
import static org.junit.Assert.assertEquals;
@@ -64,6 +69,7 @@
import android.util.Xml;
import android.view.DisplayInfo;
+import androidx.test.filters.FlakyTest;
import androidx.test.filters.MediumTest;
import com.android.internal.app.IVoiceInteractor;
@@ -102,6 +108,7 @@
public void setUp() throws Exception {
TaskRecord.setTaskRecordFactory(null);
mParentBounds = new Rect(10 /*left*/, 30 /*top*/, 80 /*right*/, 60 /*bottom*/);
+ removeGlobalMinSizeRestriction();
}
@Test
@@ -165,6 +172,7 @@
/** Ensures that bounds on freeform stacks are not clipped. */
@Test
+ @FlakyTest(bugId = 137879065)
public void testAppBounds_FreeFormBounds() {
final Rect freeFormBounds = new Rect(mParentBounds);
freeFormBounds.offset(10, 10);
@@ -174,6 +182,7 @@
/** Ensures that fully contained bounds are not clipped. */
@Test
+ @FlakyTest(bugId = 137879065)
public void testAppBounds_ContainedBounds() {
final Rect insetBounds = new Rect(mParentBounds);
insetBounds.inset(5, 5, 5, 5);
@@ -182,6 +191,7 @@
}
@Test
+ @FlakyTest(bugId = 137879065)
public void testFitWithinBounds() {
final Rect parentBounds = new Rect(10, 10, 200, 200);
ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay();
@@ -221,6 +231,7 @@
/** Tests that the task bounds adjust properly to changes between FULLSCREEN and FREEFORM */
@Test
+ @FlakyTest(bugId = 137879065)
public void testBoundsOnModeChangeFreeformToFullscreen() {
ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay();
ActivityStack stack = new StackBuilder(mRootActivityContainer).setDisplay(display)
@@ -248,18 +259,6 @@
}
/**
- * This is a temporary hack to trigger an onConfigurationChange at the task level after an
- * orientation is requested. Normally this is done by the onDescendentOrientationChanged call
- * up the WM hierarchy, but since the WM hierarchy is mocked out, it doesn't happen here.
- * TODO: remove this when we either get a WM hierarchy or when hierarchies are merged.
- */
- private void setActivityRequestedOrientation(ActivityRecord activity, int orientation) {
- activity.setRequestedOrientation(orientation);
- ConfigurationContainer taskRecord = activity.getParent();
- taskRecord.onConfigurationChanged(taskRecord.getParent().getConfiguration());
- }
-
- /**
* Tests that a task with forced orientation has orientation-consistent bounds within the
* parent.
*/
@@ -268,49 +267,48 @@
final Rect fullScreenBounds = new Rect(0, 0, 1920, 1080);
final Rect fullScreenBoundsPort = new Rect(0, 0, 1080, 1920);
DisplayInfo info = new DisplayInfo();
+ mService.mContext.getDisplay().getDisplayInfo(info);
info.logicalWidth = fullScreenBounds.width();
info.logicalHeight = fullScreenBounds.height();
ActivityDisplay display = addNewActivityDisplayAt(info, POSITION_TOP);
assertTrue(mRootActivityContainer.getActivityDisplay(display.mDisplayId) != null);
- // Override display orientation. Normally this is available via DisplayContent, but DC
- // is mocked-out.
- display.getRequestedOverrideConfiguration().orientation =
- Configuration.ORIENTATION_LANDSCAPE;
- display.onRequestedOverrideConfigurationChanged(
- display.getRequestedOverrideConfiguration());
+ // Fix the display orientation to landscape which is the natural rotation (0) for the test
+ // display.
+ final DisplayRotation dr = display.mDisplayContent.getDisplayRotation();
+ dr.setFixedToUserRotation(FIXED_TO_USER_ROTATION_ENABLED);
+ dr.setUserRotation(USER_ROTATION_FREE, ROTATION_0);
+
ActivityStack stack = new StackBuilder(mRootActivityContainer)
.setWindowingMode(WINDOWING_MODE_FULLSCREEN).setDisplay(display).build();
TaskRecord task = stack.getChildAt(0);
ActivityRecord root = task.getTopActivity();
- assertEquals(root, task.getTopActivity());
assertEquals(fullScreenBounds, task.getBounds());
// Setting app to fixed portrait fits within parent
- setActivityRequestedOrientation(root, SCREEN_ORIENTATION_PORTRAIT);
+ root.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
assertEquals(root, task.getRootActivity());
assertEquals(SCREEN_ORIENTATION_PORTRAIT, task.getRootActivity().getOrientation());
- assertTrue(task.getBounds().width() < task.getBounds().height());
+ assertThat(task.getBounds().width()).isLessThan(task.getBounds().height());
assertEquals(fullScreenBounds.height(), task.getBounds().height());
// Top activity gets used
ActivityRecord top = new ActivityBuilder(mService).setTask(task).setStack(stack).build();
assertEquals(top, task.getTopActivity());
- setActivityRequestedOrientation(top, SCREEN_ORIENTATION_LANDSCAPE);
- assertTrue(task.getBounds().width() > task.getBounds().height());
+ top.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+ assertThat(task.getBounds().width()).isGreaterThan(task.getBounds().height());
assertEquals(task.getBounds().width(), fullScreenBounds.width());
// Setting app to unspecified restores
- setActivityRequestedOrientation(top, SCREEN_ORIENTATION_UNSPECIFIED);
+ top.setRequestedOrientation(SCREEN_ORIENTATION_UNSPECIFIED);
assertEquals(fullScreenBounds, task.getBounds());
// Setting app to fixed landscape and changing display
- setActivityRequestedOrientation(top, SCREEN_ORIENTATION_LANDSCAPE);
- // simulate display orientation changing (normally done via DisplayContent)
- display.getRequestedOverrideConfiguration().orientation =
- Configuration.ORIENTATION_PORTRAIT;
- display.setBounds(fullScreenBoundsPort);
- assertTrue(task.getBounds().width() > task.getBounds().height());
+ top.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+ // Fix the display orientation to portrait which is 90 degrees for the test display.
+ dr.setUserRotation(USER_ROTATION_FREE, ROTATION_90);
+
+ assertThat(task.getBounds().width()).isGreaterThan(task.getBounds().height());
assertEquals(fullScreenBoundsPort.width(), task.getBounds().width());
// in FREEFORM, no constraint
@@ -323,7 +321,7 @@
// FULLSCREEN letterboxes bounds
stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
- assertTrue(task.getBounds().width() > task.getBounds().height());
+ assertThat(task.getBounds().width()).isGreaterThan(task.getBounds().height());
assertEquals(fullScreenBoundsPort.width(), task.getBounds().width());
// FREEFORM restores bounds as before
@@ -335,6 +333,7 @@
public void testIgnoresForcedOrientationWhenParentHandles() {
final Rect fullScreenBounds = new Rect(0, 0, 1920, 1080);
DisplayInfo info = new DisplayInfo();
+ mService.mContext.getDisplay().getDisplayInfo(info);
info.logicalWidth = fullScreenBounds.width();
info.logicalHeight = fullScreenBounds.height();
ActivityDisplay display = addNewActivityDisplayAt(info, POSITION_TOP);
@@ -355,7 +354,7 @@
// Setting app to fixed portrait fits within parent, but TaskRecord shouldn't adjust the
// bounds because its parent says it will handle it at a later time.
- setActivityRequestedOrientation(root, SCREEN_ORIENTATION_PORTRAIT);
+ root.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
assertEquals(root, task.getRootActivity());
assertEquals(SCREEN_ORIENTATION_PORTRAIT, task.getRootActivity().getOrientation());
assertEquals(fullScreenBounds, task.getBounds());
@@ -646,7 +645,7 @@
final ActivityRecord activity0 = task0.getChildAt(0);
final TaskRecord task1 = getTestTask();
- final ActivityRecord activity1 = task0.getChildAt(0);
+ final ActivityRecord activity1 = task1.getChildAt(0);
assertEquals(task0.taskId,
ActivityRecord.getTaskForActivityLocked(activity0.appToken, false /* onlyRoot */));
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestActivityDisplay.java b/services/tests/wmtests/src/com/android/server/wm/TestActivityDisplay.java
new file mode 100644
index 0000000..c143969
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/TestActivityDisplay.java
@@ -0,0 +1,101 @@
+/*
+ * 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 static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+
+import android.hardware.display.DisplayManagerGlobal;
+import android.view.Display;
+import android.view.DisplayInfo;
+
+class TestActivityDisplay extends ActivityDisplay {
+ private final ActivityStackSupervisor mSupervisor;
+
+ static TestActivityDisplay create(ActivityStackSupervisor supervisor) {
+ return create(supervisor, SystemServicesTestRule.sNextDisplayId++);
+ }
+
+ static TestActivityDisplay create(ActivityStackSupervisor supervisor, DisplayInfo info) {
+ return create(supervisor, SystemServicesTestRule.sNextDisplayId++, info);
+ }
+
+ static TestActivityDisplay create(ActivityStackSupervisor supervisor, int displayId) {
+ final DisplayInfo info = new DisplayInfo();
+ supervisor.mService.mContext.getDisplay().getDisplayInfo(info);
+ return create(supervisor, displayId, info);
+ }
+
+ static TestActivityDisplay create(ActivityStackSupervisor supervisor, int displayId,
+ DisplayInfo info) {
+ if (displayId == DEFAULT_DISPLAY) {
+ synchronized (supervisor.mService.mGlobalLock) {
+ return new TestActivityDisplay(supervisor,
+ supervisor.mRootActivityContainer.mDisplayManager.getDisplay(displayId));
+ }
+ }
+ final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId,
+ info, DEFAULT_DISPLAY_ADJUSTMENTS);
+
+ synchronized (supervisor.mService.mGlobalLock) {
+ return new TestActivityDisplay(supervisor, display);
+ }
+ }
+
+ private TestActivityDisplay(ActivityStackSupervisor supervisor, Display display) {
+ super(supervisor.mService.mRootActivityContainer, display);
+ // Normally this comes from display-properties as exposed by WM. Without that, just
+ // hard-code to FULLSCREEN for tests.
+ setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ mSupervisor = supervisor;
+ spyOn(this);
+ spyOn(mDisplayContent);
+ doAnswer(invocation -> {
+ // Bypass all the rotation animation and display freezing stuff for testing and just
+ // set the rotation we want for the display
+ final DisplayContent dc = mDisplayContent;
+ final int oldRotation = dc.getRotation();
+ final int rotation = dc.getDisplayRotation().rotationForOrientation(
+ dc.getLastOrientation(), oldRotation);
+ if (oldRotation == rotation) {
+ return false;
+ }
+ dc.setLayoutNeeded();
+ dc.setRotation(rotation);
+ return true;
+ }).when(mDisplayContent).updateRotationUnchecked(anyBoolean());
+ }
+
+ @SuppressWarnings("TypeParameterUnusedInFormals")
+ @Override
+ ActivityStack createStackUnchecked(int windowingMode, int activityType,
+ int stackId, boolean onTop) {
+ return new ActivityTestsBase.StackBuilder(mSupervisor.mRootActivityContainer)
+ .setDisplay(this)
+ .setWindowingMode(windowingMode)
+ .setActivityType(activityType)
+ .setStackId(stackId)
+ .setOnTop(onTop)
+ .setCreateActivity(false)
+ .build();
+ }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 2e5ce69..bb89446 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -40,12 +40,14 @@
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.IShortcutService;
import com.android.server.policy.WindowManagerPolicy;
+import com.android.server.wm.WindowState.PowerManagerWrapper;
import java.io.PrintWriter;
import java.util.function.Supplier;
class TestWindowManagerPolicy implements WindowManagerPolicy {
private final Supplier<WindowManagerService> mWmSupplier;
+ private final PowerManagerWrapper mPowerManagerWrapper;
int mRotationToReport = 0;
boolean mKeyguardShowingAndNotOccluded = false;
@@ -53,8 +55,10 @@
private Runnable mRunnableWhenAddingSplashScreen;
- TestWindowManagerPolicy(Supplier<WindowManagerService> wmSupplier) {
+ TestWindowManagerPolicy(Supplier<WindowManagerService> wmSupplier,
+ PowerManagerWrapper powerManagerWrapper) {
mWmSupplier = wmSupplier;
+ mPowerManagerWrapper = powerManagerWrapper;
}
@Override
@@ -121,7 +125,7 @@
doReturn(mock(IBinder.class)).when(iWindow).asBinder();
window = WindowTestsBase.createWindow(null, TYPE_APPLICATION_STARTING, atoken,
"Starting window", 0 /* ownerId */, false /* internalWindows */, wm,
- mock(Session.class), iWindow);
+ mock(Session.class), iWindow, mPowerManagerWrapper);
atoken.startingWindow = window;
}
if (mRunnableWhenAddingSplashScreen != null) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index acfc2ea..921f105 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -27,6 +27,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
@@ -113,6 +114,7 @@
@Test
public void testAddChildSetsSurfacePosition() {
+ reset(mTransaction);
try (MockSurfaceBuildingContainer top = new MockSurfaceBuildingContainer(mWm)) {
WindowContainer child = new WindowContainer(mWm);
child.setBounds(1, 1, 10, 10);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
index 06bcdf8..60cefe8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
@@ -57,6 +57,7 @@
private final IWindow mIWindow = new TestIWindow();
private final Rect mEmptyRect = new Rect();
+ private DisplayContent mTestDisplayContent;
static class FrameTestWindowState extends WindowState {
boolean mDockedResizingForTest = false;
@@ -77,6 +78,9 @@
@Before
public void setUp() throws Exception {
mStubStack = mock(TaskStack.class);
+ DisplayInfo testDisplayInfo = new DisplayInfo(mDisplayInfo);
+ testDisplayInfo.displayCutout = null;
+ mTestDisplayContent = createNewDisplay(testDisplayInfo);
}
// Do not use this function directly in the tests below. Instead, use more explicit function
@@ -100,6 +104,10 @@
assertRect(w.getStableInsets(), left, top, right, bottom);
}
+ private void assertFrame(WindowState w, Rect frame) {
+ assertEquals(w.getFrameLw(), frame);
+ }
+
private void assertFrame(WindowState w, int left, int top, int right, int bottom) {
assertRect(w.getFrameLw(), left, top, right, bottom);
}
@@ -380,9 +388,10 @@
}
@Test
+ @FlakyTest(bugId = 137879065)
public void testLayoutLetterboxedWindow() {
// First verify task behavior in multi-window mode.
- final DisplayInfo displayInfo = mWm.getDefaultDisplayContentLocked().getDisplayInfo();
+ final DisplayInfo displayInfo = mTestDisplayContent.getDisplayInfo();
final int logicalWidth = displayInfo.logicalWidth;
final int logicalHeight = displayInfo.logicalHeight;
@@ -413,13 +422,14 @@
final Rect cf = new Rect(xInset, 0, logicalWidth - xInset, logicalHeight);
Configuration config = new Configuration(w.mAppToken.getRequestedOverrideConfiguration());
config.windowConfiguration.setBounds(cf);
+ config.windowConfiguration.setAppBounds(cf);
w.mAppToken.onRequestedOverrideConfigurationChanged(config);
pf.set(0, 0, logicalWidth, logicalHeight);
task.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
task.setBounds(null);
windowFrames.setFrames(pf, pf, pf, cf, cf, pf, cf, mEmptyRect);
w.computeFrameLw();
- assertFrame(w, cf.left, cf.top, cf.right, cf.bottom);
+ assertFrame(w, cf);
assertContentFrame(w, cf);
assertContentInset(w, 0, 0, 0, 0);
}
@@ -483,7 +493,7 @@
w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
task.setWindowingMode(WINDOWING_MODE_FREEFORM);
- DisplayContent dc = mWm.getDefaultDisplayContentLocked();
+ DisplayContent dc = mTestDisplayContent;
dc.mInputMethodTarget = w;
WindowState mockIme = mock(WindowState.class);
Mockito.doReturn(true).when(mockIme).isVisibleNow();
@@ -537,7 +547,7 @@
attrs.width = width;
attrs.height = height;
- AppWindowToken token = createAppWindowToken(mWm.getDefaultDisplayContentLocked(),
+ AppWindowToken token = createAppWindowToken(mTestDisplayContent,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
FrameTestWindowState ws = new FrameTestWindowState(mWm, mIWindow, token, attrs);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 36698ea..b731628 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -346,24 +346,28 @@
firstWindow.mAttrs.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
secondWindow.mAttrs.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
- reset(sPowerManagerWrapper);
+ final WindowState.PowerManagerWrapper powerManagerWrapper =
+ mSystemServicesTestRule.getPowerManagerWrapper();
+ reset(powerManagerWrapper);
firstWindow.prepareWindowToDisplayDuringRelayout(false /*wasVisible*/);
- verify(sPowerManagerWrapper).wakeUp(anyLong(), anyInt(), anyString());
+ verify(powerManagerWrapper).wakeUp(anyLong(), anyInt(), anyString());
- reset(sPowerManagerWrapper);
+ reset(powerManagerWrapper);
secondWindow.prepareWindowToDisplayDuringRelayout(false /*wasVisible*/);
- verify(sPowerManagerWrapper).wakeUp(anyLong(), anyInt(), anyString());
+ verify(powerManagerWrapper).wakeUp(anyLong(), anyInt(), anyString());
}
private void testPrepareWindowToDisplayDuringRelayout(WindowState appWindow,
boolean expectedWakeupCalled, boolean expectedCurrentLaunchCanTurnScreenOn) {
- reset(sPowerManagerWrapper);
+ final WindowState.PowerManagerWrapper powerManagerWrapper =
+ mSystemServicesTestRule.getPowerManagerWrapper();
+ reset(powerManagerWrapper);
appWindow.prepareWindowToDisplayDuringRelayout(false /* wasVisible */);
if (expectedWakeupCalled) {
- verify(sPowerManagerWrapper).wakeUp(anyLong(), anyInt(), anyString());
+ verify(powerManagerWrapper).wakeUp(anyLong(), anyInt(), anyString());
} else {
- verify(sPowerManagerWrapper, never()).wakeUp(anyLong(), anyInt(), anyString());
+ verify(powerManagerWrapper, never()).wakeUp(anyLong(), anyInt(), anyString());
}
// If wakeup is expected to be called, the currentLaunchCanTurnScreenOn should be false
// because the state will be consumed.
@@ -517,13 +521,19 @@
@Test
public void testGetTransformationMatrix() {
+ final int PARENT_WINDOW_OFFSET = 1;
+ final int DISPLAY_IN_PARENT_WINDOW_OFFSET = 2;
+ final int WINDOW_OFFSET = 3;
+ final float OFFSET_SUM =
+ PARENT_WINDOW_OFFSET + DISPLAY_IN_PARENT_WINDOW_OFFSET + WINDOW_OFFSET;
+
synchronized (mWm.mGlobalLock) {
final WindowState win0 = createWindow(null, TYPE_APPLICATION, "win0");
- win0.getFrameLw().offsetTo(1, 0);
final DisplayContent dc = createNewDisplay();
+ win0.getFrameLw().offsetTo(PARENT_WINDOW_OFFSET, 0);
dc.reparentDisplayContent(win0, win0.getSurfaceControl());
- dc.updateLocation(win0, 2, 0);
+ dc.updateLocation(win0, DISPLAY_IN_PARENT_WINDOW_OFFSET, 0);
final float[] values = new float[9];
final Matrix matrix = new Matrix();
@@ -531,12 +541,12 @@
final WindowState win1 = createWindow(null, TYPE_APPLICATION, dc, "win1");
win1.mHasSurface = true;
win1.mSurfaceControl = mock(SurfaceControl.class);
- win1.getFrameLw().offsetTo(3, 0);
+ win1.getFrameLw().offsetTo(WINDOW_OFFSET, 0);
win1.updateSurfacePosition(t);
win1.getTransformationMatrix(values, matrix);
matrix.getValues(values);
- assertEquals(6f, values[Matrix.MTRANS_X], 0f);
+ assertEquals(OFFSET_SUM, values[Matrix.MTRANS_X], 0f);
assertEquals(0f, values[Matrix.MTRANS_Y], 0f);
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index dc461d1..d1cf1c3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -20,8 +20,6 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.os.Process.SYSTEM_UID;
-import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
import static android.view.View.VISIBLE;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
@@ -38,33 +36,27 @@
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
+import static com.android.server.wm.ActivityDisplay.POSITION_TOP;
import static org.mockito.Mockito.mock;
-
import android.content.Context;
import android.content.res.Configuration;
-import android.hardware.display.DisplayManagerGlobal;
import android.testing.DexmakerShareClassLoaderRule;
import android.util.Log;
import android.view.Display;
import android.view.DisplayInfo;
import android.view.IWindow;
-import android.view.Surface;
import android.view.SurfaceControl.Transaction;
import android.view.WindowManager;
import com.android.server.AttributeCache;
-import com.android.server.wm.utils.MockTracker;
import org.junit.After;
-import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
-import java.io.IOException;
import java.util.HashSet;
import java.util.LinkedList;
@@ -79,10 +71,6 @@
WindowManagerService mWm;
private final IWindow mIWindow = new TestIWindow();
private Session mMockSession;
- // The default display is removed in {@link #setUp} and then we iterate over all displays to
- // make sure we don't collide with any existing display. If we run into no other display, the
- // added display should be treated as default. This cannot be the default display
- private static int sNextDisplayId = DEFAULT_DISPLAY + 1;
static int sNextStackId = 1000;
/** Non-default display. */
@@ -99,8 +87,6 @@
WindowState mChildAppWindowBelow;
HashSet<WindowState> mCommonWindows;
- private MockTracker mMockTracker;
-
/**
* Spied {@link Transaction} class than can be used to verify calls.
*/
@@ -112,49 +98,27 @@
@Rule
public final SystemServicesTestRule mSystemServicesTestRule = new SystemServicesTestRule();
- static WindowState.PowerManagerWrapper sPowerManagerWrapper;
-
@BeforeClass
public static void setUpOnceBase() {
AttributeCache.init(getInstrumentation().getTargetContext());
-
- sPowerManagerWrapper = mock(WindowState.PowerManagerWrapper.class);
- }
-
- @AfterClass
- public static void tearDownOnceBase() throws IOException {
- sPowerManagerWrapper = null;
}
@Before
public void setUpBase() {
- mMockTracker = new MockTracker();
-
// If @Before throws an exception, the error isn't logged. This will make sure any failures
// in the set up are clear. This can be removed when b/37850063 is fixed.
try {
mMockSession = mock(Session.class);
- mTransaction = spy(StubTransaction.class);
final Context context = getInstrumentation().getTargetContext();
mWm = mSystemServicesTestRule.getWindowManagerService();
-
- // Setup factory classes to prevent calls to native code.
-
- // Return a spied Transaction class than can be used to verify calls.
- mWm.mTransactionFactory = () -> mTransaction;
- // Return a SurfaceControl.Builder class that creates mocked SurfaceControl instances.
- mWm.mSurfaceBuilderFactory = (unused) -> new MockSurfaceControlBuilder();
- // Return mocked Surface instances.
- mWm.mSurfaceFactory = () -> mock(Surface.class);
+ mTransaction = mSystemServicesTestRule.mTransaction;
beforeCreateDisplay();
context.getDisplay().getDisplayInfo(mDisplayInfo);
mDisplayContent = createNewDisplay();
- mWm.mDisplayEnabled = true;
- mWm.mDisplayReady = true;
// Set-up some common windows.
mCommonWindows = new HashSet<>();
@@ -211,12 +175,6 @@
nonCommonWindows.pollLast().removeImmediately();
}
- for (int i = mWm.mRoot.mChildren.size() - 1; i >= 0; --i) {
- final DisplayContent displayContent = mWm.mRoot.mChildren.get(i);
- if (!displayContent.isDefaultDisplay) {
- displayContent.removeImmediately();
- }
- }
// Remove app transition & window freeze timeout callbacks to prevent unnecessary
// actions after test.
mWm.getDefaultDisplayContentLocked().mAppTransition
@@ -230,11 +188,7 @@
} catch (Exception e) {
Log.e(TAG, "Failed to tear down test", e);
throw e;
- } finally {
- mMockTracker.close();
- mMockTracker = null;
}
-
}
private WindowState createCommonWindow(WindowState parent, int type, String name) {
@@ -356,12 +310,13 @@
WindowState createWindow(WindowState parent, int type, WindowToken token, String name,
int ownerId, boolean ownerCanAddInternalSystemWindow) {
return createWindow(parent, type, token, name, ownerId, ownerCanAddInternalSystemWindow,
- mWm, mMockSession, mIWindow);
+ mWm, mMockSession, mIWindow, mSystemServicesTestRule.getPowerManagerWrapper());
}
static WindowState createWindow(WindowState parent, int type, WindowToken token,
String name, int ownerId, boolean ownerCanAddInternalSystemWindow,
- WindowManagerService service, Session session, IWindow iWindow) {
+ WindowManagerService service, Session session, IWindow iWindow,
+ WindowState.PowerManagerWrapper powerManagerWrapper) {
synchronized (service.mGlobalLock) {
final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type);
attrs.setTitle(name);
@@ -369,7 +324,7 @@
final WindowState w = new WindowState(service, session, iWindow, token, parent,
OP_NONE,
0, attrs, VISIBLE, ownerId, ownerCanAddInternalSystemWindow,
- sPowerManagerWrapper);
+ powerManagerWrapper);
// TODO: Probably better to make this call in the WindowState ctor to avoid errors with
// adding it to the token...
token.addWindow(w);
@@ -408,13 +363,11 @@
}
/** Creates a {@link DisplayContent} and adds it to the system. */
- DisplayContent createNewDisplay(DisplayInfo displayInfo) {
- final int displayId = sNextDisplayId++;
- final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId,
- displayInfo, DEFAULT_DISPLAY_ADJUSTMENTS);
- synchronized (mWm.mGlobalLock) {
- return new DisplayContent(display, mWm, mock(ActivityDisplay.class));
- }
+ DisplayContent createNewDisplay(DisplayInfo info) {
+ final ActivityDisplay display =
+ TestActivityDisplay.create(mWm.mAtmService.mStackSupervisor, info);
+ mWm.mAtmService.mRootActivityContainer.addChild(display, POSITION_TOP);
+ return display.mDisplayContent;
}
/**
@@ -428,17 +381,7 @@
DisplayInfo displayInfo = new DisplayInfo();
displayInfo.copyFrom(mDisplayInfo);
displayInfo.state = displayState;
- final int displayId = sNextDisplayId++;
- final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId,
- displayInfo, DEFAULT_DISPLAY_ADJUSTMENTS);
- synchronized (mWm.mGlobalLock) {
- // Display creation is driven by DisplayWindowController via ActivityStackSupervisor.
- // We skip those steps here.
- final ActivityDisplay mockAd = mock(ActivityDisplay.class);
- final DisplayContent displayContent = mWm.mRoot.createDisplayContent(display, mockAd);
- displayContent.reconfigureDisplayLocked();
- return displayContent;
- }
+ return createNewDisplay(displayInfo);
}
/** Creates a {@link com.android.server.wm.WindowTestUtils.TestWindowState} */
diff --git a/services/tests/wmtests/src/com/android/server/wm/utils/MockTracker.java b/services/tests/wmtests/src/com/android/server/wm/utils/MockTracker.java
index a6e675a..7f09482 100644
--- a/services/tests/wmtests/src/com/android/server/wm/utils/MockTracker.java
+++ b/services/tests/wmtests/src/com/android/server/wm/utils/MockTracker.java
@@ -89,7 +89,7 @@
for (final Object mock : mMocks.keySet()) {
if (MockUtil.isMock(mock)) {
- Mockito.reset(mock);
+ mMockitoFramework.clearInlineMock(mock);
}
}
mMocks.clear();
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index b2fde54..b2ac549 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -20,6 +20,7 @@
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.AppGlobals;
@@ -36,6 +37,7 @@
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.ShortcutServiceInternal;
+import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.hardware.soundtrigger.IRecognitionStatusCallback;
@@ -80,6 +82,7 @@
import com.android.server.UiThread;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
import com.android.server.soundtrigger.SoundTriggerInternal;
+import com.android.server.utils.TimingsTraceAndSlog;
import com.android.server.wm.ActivityTaskManagerInternal;
import java.io.FileDescriptor;
@@ -92,7 +95,7 @@
*/
public class VoiceInteractionManagerService extends SystemService {
static final String TAG = "VoiceInteractionManagerService";
- static final boolean DEBUG = false;
+ static final boolean DEBUG = true; // TODO(b/133242016) STOPSHIP: change to false before R ships
final Context mContext;
final ContentResolver mResolver;
@@ -154,19 +157,37 @@
}
@Override
- public void onStartUser(int userHandle) {
- mServiceStub.initForUser(userHandle);
+ public void onStartUser(@NonNull UserInfo userInfo) {
+ if (DEBUG) Slog.d(TAG, "onStartUser(" + userInfo + ")");
+
+ if (!userInfo.isFull()) {
+ if (DEBUG) Slog.d(TAG, "***** skipping on non-full user " + userInfo);
+ return;
+ }
+ mServiceStub.initForUser(userInfo.id);
}
@Override
- public void onUnlockUser(int userHandle) {
- mServiceStub.initForUser(userHandle);
+ public void onUnlockUser(@NonNull UserInfo userInfo) {
+ if (DEBUG) Slog.d(TAG, "onUnlockUser(" + userInfo + ")");
+
+ if (!userInfo.isFull()) {
+ if (DEBUG) Slog.d(TAG, "***** skipping on non-full user " + userInfo);
+ return;
+ }
+ mServiceStub.initForUser(userInfo.id);
mServiceStub.switchImplementationIfNeeded(false);
}
@Override
- public void onSwitchUser(int userHandle) {
- mServiceStub.switchUser(userHandle);
+ public void onSwitchUser(@NonNull UserInfo userInfo) {
+ if (DEBUG) Slog.d(TAG, "onSwitchUser(" + userInfo + ")");
+
+ if (!userInfo.isFull()) {
+ if (DEBUG) Slog.d(TAG, "***** skipping on non-full user " + userInfo);
+ return;
+ }
+ mServiceStub.switchUser(userInfo.id);
}
class LocalService extends VoiceInteractionManagerInternal {
@@ -270,6 +291,20 @@
}
public void initForUser(int userHandle) {
+ final TimingsTraceAndSlog t;
+ if (DEBUG) {
+ t = TimingsTraceAndSlog.newAsyncLog();
+ t.traceBegin("VoiceInteractionSvc.initForUser(" + userHandle + ")");
+ } else {
+ t = null;
+ }
+ initForUserNoTracing(userHandle);
+ if (t != null) {
+ t.traceEnd();
+ }
+ }
+
+ private void initForUserNoTracing(@UserIdInt int userHandle) {
if (DEBUG) Slog.d(TAG, "**************** initForUser user=" + userHandle);
String curInteractorStr = Settings.Secure.getStringForUser(
mContext.getContentResolver(),
@@ -426,6 +461,20 @@
}
void switchImplementationIfNeededLocked(boolean force) {
+ final TimingsTraceAndSlog t;
+ if (DEBUG) {
+ t = TimingsTraceAndSlog.newAsyncLog();
+ t.traceBegin("VoiceInteractionSvc.switchImplementation(" + mCurUser + ")");
+ } else {
+ t = null;
+ }
+ switchImplementationIfNeededNoTracingLocked(force);
+ if (t != null) {
+ t.traceEnd();
+ }
+ }
+
+ void switchImplementationIfNeededNoTracingLocked(boolean force) {
if (!mSafeMode) {
String curService = Settings.Secure.getStringForUser(
mResolver, Settings.Secure.VOICE_INTERACTION_SERVICE, mCurUser);
diff --git a/services/wifi/Android.bp b/services/wifi/Android.bp
new file mode 100644
index 0000000..3c916a6
--- /dev/null
+++ b/services/wifi/Android.bp
@@ -0,0 +1,11 @@
+// Interfaces between the core system and the wifi mainline module.
+java_library_static {
+ name: "services.wifi",
+ srcs: [
+ "java/**/*.java",
+ "java/**/*.aidl",
+ ],
+ libs: [
+ "services.net",
+ ],
+}
diff --git a/services/wifi/java/android/net/wifi/IWifiStackConnector.aidl b/services/wifi/java/android/net/wifi/IWifiStackConnector.aidl
new file mode 100644
index 0000000..eadc726
--- /dev/null
+++ b/services/wifi/java/android/net/wifi/IWifiStackConnector.aidl
@@ -0,0 +1,22 @@
+/**
+ * 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 perNmissions and
+ * limitations under the License.
+ */
+package android.net.wifi;
+
+/** @hide */
+interface IWifiStackConnector {
+ IBinder retrieveApiServiceImpl(String serviceName);
+ boolean startApiService(String serviceName);
+}
diff --git a/services/wifi/java/android/net/wifi/WifiStackClient.java b/services/wifi/java/android/net/wifi/WifiStackClient.java
new file mode 100644
index 0000000..fa66e4c
--- /dev/null
+++ b/services/wifi/java/android/net/wifi/WifiStackClient.java
@@ -0,0 +1,115 @@
+/*
+ * 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.net.wifi;
+
+import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH;
+import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.net.ConnectivityModuleConnector;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+/**
+ * Service used to communicate with the wifi stack, which could be running in a separate
+ * module.
+ * @hide
+ */
+public class WifiStackClient {
+ public static final String PERMISSION_MAINLINE_WIFI_STACK =
+ "android.permission.MAINLINE_WIFI_STACK";
+
+ private static final String TAG = WifiStackClient.class.getSimpleName();
+ private static WifiStackClient sInstance;
+
+ private WifiStackClient() { }
+
+ /**
+ * Get the WifiStackClient singleton instance.
+ */
+ public static synchronized WifiStackClient getInstance() {
+ if (sInstance == null) {
+ sInstance = new WifiStackClient();
+ }
+ return sInstance;
+ }
+
+ private class WifiStackConnection implements
+ ConnectivityModuleConnector.ModuleServiceCallback {
+ @Override
+ public void onModuleServiceConnected(IBinder service) {
+ Log.i(TAG, "Wifi stack connected");
+
+ registerWifiStackService(service);
+ IWifiStackConnector connector = IWifiStackConnector.Stub.asInterface(service);
+ registerApiServiceAndStart(connector, Context.WIFI_SERVICE);
+ registerApiServiceAndStart(connector, Context.WIFI_SCANNING_SERVICE);
+ registerApiServiceAndStart(connector, Context.WIFI_P2P_SERVICE);
+ registerApiServiceAndStart(connector, Context.WIFI_AWARE_SERVICE);
+ registerApiServiceAndStart(connector, Context.WIFI_RTT_RANGING_SERVICE);
+ }
+ }
+
+ private void registerWifiStackService(@NonNull IBinder service) {
+ ServiceManager.addService(Context.WIFI_STACK_SERVICE, service,
+ false /* allowIsolated */,
+ DUMP_FLAG_PRIORITY_HIGH | DUMP_FLAG_PRIORITY_NORMAL);
+ Log.i(TAG, "Wifi stack service registered");
+ }
+
+ private void registerApiServiceAndStart(
+ IWifiStackConnector stackConnector, String serviceName) {
+ IBinder service = null;
+ try {
+ service = stackConnector.retrieveApiServiceImpl(serviceName);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Failed to retrieve service impl " + serviceName, e);
+ }
+ if (service == null) {
+ Log.i(TAG, "Service " + serviceName + " not available");
+ return;
+ }
+ Log.i(TAG, "Registering " + serviceName);
+ ServiceManager.addService(serviceName, service);
+
+ boolean success = false;
+ try {
+ success = stackConnector.startApiService(serviceName);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Failed to start service " + serviceName, e);
+ }
+ if (!success) {
+ throw new RuntimeException("Service " + serviceName + " start failed");
+ }
+ }
+
+ /**
+ * Start the wifi stack. Should be called only once on device startup.
+ *
+ * <p>This method will start the wifi stack either in the wifi stack
+ * process, or inside the system server on devices that do not support the wifi stack
+ * module.
+ */
+ public void start() {
+ Log.i(TAG, "Starting wifi stack");
+ ConnectivityModuleConnector.getInstance().startModuleService(
+ IWifiStackConnector.class.getName(), PERMISSION_MAINLINE_WIFI_STACK,
+ new WifiStackConnection());
+ }
+}
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index 43fb304..42a5501 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -692,7 +692,7 @@
}
/**
- * Contains all sent text-based SMS messages in the SMS app.
+ * Contains all draft text-based SMS messages in the SMS app.
*/
public static final class Draft implements BaseColumns, TextBasedSmsColumns {
@@ -808,7 +808,15 @@
}
/**
- * Contains all sent text-based SMS messages in the SMS app.
+ * Contains a view of SMS conversations (also referred to as threads). This is similar to
+ * {@link Threads}, but only includes SMS messages and columns relevant to SMS
+ * conversations.
+ * <p>
+ * Note that this view ignores any information about MMS messages, it is a
+ * view of conversations as if MMS messages did not exist at all. This means that all
+ * relevant information, such as snippets and message count, will ignore any MMS messages
+ * that might be in the same thread through other views and present only data based on the
+ * SMS messages in that thread.
*/
public static final class Conversations
implements BaseColumns, TextBasedSmsColumns {
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 60de214..10d4b8db 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2656,25 +2656,32 @@
"call_waiting_service_class_int";
/**
- * This configuration allow the system UI to display different 5G icon for different 5G status.
+ * This configuration allow the system UI to display different 5G icon for different 5G
+ * scenario.
*
- * There are four 5G status:
+ * There are five 5G scenarios:
* 1. connected_mmwave: device currently connected to 5G cell as the secondary cell and using
* millimeter wave.
* 2. connected: device currently connected to 5G cell as the secondary cell but not using
* millimeter wave.
- * 3. not_restricted: device camped on a network that has 5G capability(not necessary to connect
- * a 5G cell as a secondary cell) and the use of 5G is not restricted.
- * 4. restricted: device camped on a network that has 5G capability(not necessary to connect a
+ * 3. not_restricted_rrc_idle: device camped on a network that has 5G capability(not necessary
+ * to connect a 5G cell as a secondary cell) and the use of 5G is not restricted and RRC
+ * currently in IDLE state.
+ * 4. not_restricted_rrc_con: device camped on a network that has 5G capability(not necessary
+ * to connect a 5G cell as a secondary cell) and the use of 5G is not restricted and RRC
+ * currently in CONNECTED state.
+ * 5. restricted: device camped on a network that has 5G capability(not necessary to connect a
* 5G cell as a secondary cell) but the use of 5G is restricted.
*
* The configured string contains multiple key-value pairs separated by comma. For each pair,
* the key and value is separated by a colon. The key is corresponded to a 5G status above and
* the value is the icon name. Use "None" as the icon name if no icon should be shown in a
- * specific 5G status.
+ * specific 5G scenario. If the scenario is "None", config can skip this key and value.
*
- * Here is an example of the configuration:
- * "connected_mmwave:5GPlus,connected:5G,not_restricted:None,restricted:None"
+ * Here is an example:
+ * UE want to display 5GPlus icon for scenario#1, and 5G icon for scenario#2; otherwise no
+ * define.
+ * The configuration is: "connected_mmwave:5GPlus,connected:5G"
*
* @hide
*/
@@ -3131,6 +3138,13 @@
public static final String KEY_SUPPORT_WPS_OVER_IMS_BOOL =
"support_wps_over_ims_bool";
+ /**
+ * Holds the list of carrier certificate hashes. Note that each carrier has its own certificates
+ * @hide
+ */
+ public static final String KEY_CARRIER_CERTIFICATE_STRING_ARRAY =
+ "carrier_certificate_string_array";
+
/** The default value for every variable. */
private final static PersistableBundle sDefaults;
@@ -3509,7 +3523,7 @@
sDefaults.putBoolean(KEY_USE_CALLER_ID_USSD_BOOL, false);
sDefaults.putInt(KEY_CALL_WAITING_SERVICE_CLASS_INT, 1 /* SERVICE_CLASS_VOICE */);
sDefaults.putString(KEY_5G_ICON_CONFIGURATION_STRING,
- "connected_mmwave:None,connected:5G,not_restricted:None,restricted:None");
+ "connected_mmwave:5G,connected:5G");
sDefaults.putInt(KEY_5G_ICON_DISPLAY_GRACE_PERIOD_SEC_INT, 0);
sDefaults.putBoolean(KEY_ASCII_7_BIT_SUPPORT_FOR_LONG_MESSAGE_BOOL, false);
/* Default value is minimum RSRP level needed for SIGNAL_STRENGTH_GOOD */
@@ -3552,6 +3566,7 @@
});
sDefaults.putBoolean(KEY_SUPPORT_WPS_OVER_IMS_BOOL, true);
sDefaults.putAll(Ims.getDefaults());
+ sDefaults.putStringArray(KEY_CARRIER_CERTIFICATE_STRING_ARRAY, null);
}
/**
diff --git a/telephony/java/android/telephony/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java
index 258a873..432978d 100644
--- a/telephony/java/android/telephony/CellIdentity.java
+++ b/telephony/java/android/telephony/CellIdentity.java
@@ -17,6 +17,7 @@
package android.telephony;
import android.annotation.CallSuper;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
@@ -61,7 +62,7 @@
mType = type;
// Only allow INT_MAX if unknown string mcc/mnc
- if (mcc == null || mcc.matches("^[0-9]{3}$")) {
+ if (mcc == null || isMcc(mcc)) {
mMccStr = mcc;
} else if (mcc.isEmpty() || mcc.equals(String.valueOf(Integer.MAX_VALUE))) {
// If the mccStr is empty or unknown, set it as null.
@@ -73,7 +74,7 @@
log("invalid MCC format: " + mcc);
}
- if (mnc == null || mnc.matches("^[0-9]{2,3}$")) {
+ if (mnc == null || isMnc(mnc)) {
mMncStr = mnc;
} else if (mnc.isEmpty() || mnc.equals(String.valueOf(Integer.MAX_VALUE))) {
// If the mncStr is empty or unknown, set it as null.
@@ -262,4 +263,30 @@
if ((value < rangeMin || value > rangeMax) && value != special) return CellInfo.UNAVAILABLE;
return value;
}
+
+ /** @hide */
+ private static boolean isMcc(@NonNull String mcc) {
+ // ensure no out of bounds indexing
+ if (mcc.length() != 3) return false;
+
+ // Character.isDigit allows all unicode digits, not just [0-9]
+ for (int i = 0; i < 3; i++) {
+ if (mcc.charAt(i) < '0' || mcc.charAt(i) > '9') return false;
+ }
+
+ return true;
+ }
+
+ /** @hide */
+ private static boolean isMnc(@NonNull String mnc) {
+ // ensure no out of bounds indexing
+ if (mnc.length() < 2 || mnc.length() > 3) return false;
+
+ // Character.isDigit allows all unicode digits, not just [0-9]
+ for (int i = 0; i < mnc.length(); i++) {
+ if (mnc.charAt(i) < '0' || mnc.charAt(i) > '9') return false;
+ }
+
+ return true;
+ }
}
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index a8491d3..36e8123 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -38,6 +38,7 @@
import android.util.DisplayMetrics;
import android.util.Log;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -147,7 +148,14 @@
* The access rules for this subscription, if it is embedded and defines any.
*/
@Nullable
- private UiccAccessRule[] mAccessRules;
+ private UiccAccessRule[] mNativeAccessRules;
+
+ /**
+ * The carrier certificates for this subscription that are saved in carrier configs.
+ * The other carrier certificates are embedded on Uicc and stored as part of mNativeAccessRules.
+ */
+ @Nullable
+ private UiccAccessRule[] mCarrierConfigAccessRules;
/**
* The string ID of the SIM card. It is the ICCID of the active profile for a UICC card and the
@@ -206,12 +214,12 @@
public SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName,
CharSequence carrierName, int nameSource, int iconTint, String number, int roaming,
Bitmap icon, String mcc, String mnc, String countryIso, boolean isEmbedded,
- @Nullable UiccAccessRule[] accessRules, String cardString) {
+ @Nullable UiccAccessRule[] nativeAccessRules, String cardString) {
this(id, iccId, simSlotIndex, displayName, carrierName, nameSource, iconTint, number,
- roaming, icon, mcc, mnc, countryIso, isEmbedded, accessRules, cardString, -1,
+ 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);
+ SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM, null, null);
}
/**
@@ -220,12 +228,12 @@
public SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName,
CharSequence carrierName, int nameSource, int iconTint, String number, int roaming,
Bitmap icon, String mcc, String mnc, String countryIso, boolean isEmbedded,
- @Nullable UiccAccessRule[] accessRules, String cardString, boolean isOpportunistic,
- @Nullable String groupUUID, int carrierId, int profileClass) {
+ @Nullable UiccAccessRule[] nativeAccessRules, String cardString,
+ boolean isOpportunistic, @Nullable String groupUUID, int carrierId, int profileClass) {
this(id, iccId, simSlotIndex, displayName, carrierName, nameSource, iconTint, number,
- roaming, icon, mcc, mnc, countryIso, isEmbedded, accessRules, cardString, -1,
+ roaming, icon, mcc, mnc, countryIso, isEmbedded, nativeAccessRules, cardString, -1,
isOpportunistic, groupUUID, false, carrierId, profileClass,
- SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM, null);
+ SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM, null, null);
}
/**
@@ -234,9 +242,10 @@
public SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName,
CharSequence carrierName, int nameSource, int iconTint, String number, int roaming,
Bitmap icon, String mcc, String mnc, String countryIso, boolean isEmbedded,
- @Nullable UiccAccessRule[] accessRules, String cardString, int cardId,
+ @Nullable UiccAccessRule[] nativeAccessRules, String cardString, int cardId,
boolean isOpportunistic, @Nullable String groupUUID, boolean isGroupDisabled,
- int carrierId, int profileClass, int subType, @Nullable String groupOwner) {
+ int carrierId, int profileClass, int subType, @Nullable String groupOwner,
+ @Nullable UiccAccessRule[] carrierConfigAccessRules) {
this.mId = id;
this.mIccId = iccId;
this.mSimSlotIndex = simSlotIndex;
@@ -251,7 +260,7 @@
this.mMnc = mnc;
this.mCountryIso = countryIso;
this.mIsEmbedded = isEmbedded;
- this.mAccessRules = accessRules;
+ this.mNativeAccessRules = nativeAccessRules;
this.mCardString = cardString;
this.mCardId = cardId;
this.mIsOpportunistic = isOpportunistic;
@@ -261,6 +270,7 @@
this.mProfileClass = profileClass;
this.mSubscriptionType = subType;
this.mGroupOwner = groupOwner;
+ this.mCarrierConfigAccessRules = carrierConfigAccessRules;
}
/**
@@ -566,7 +576,8 @@
if (!isEmbedded()) {
throw new UnsupportedOperationException("Not an embedded subscription");
}
- if (mAccessRules == null) {
+ List<UiccAccessRule> allAccessRules = getAllAccessRules();
+ if (allAccessRules == null) {
return false;
}
PackageManager packageManager = context.getPackageManager();
@@ -576,7 +587,7 @@
} catch (PackageManager.NameNotFoundException e) {
throw new IllegalArgumentException("Unknown package: " + packageName, e);
}
- for (UiccAccessRule rule : mAccessRules) {
+ for (UiccAccessRule rule : allAccessRules) {
if (rule.getCarrierPrivilegeStatus(packageInfo)
== TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
return true;
@@ -586,7 +597,10 @@
}
/**
- * @return the {@link UiccAccessRule}s dictating who is authorized to manage this subscription.
+ * @return the {@link UiccAccessRule}s that are stored in Uicc, dictating who
+ * is authorized to manage this subscription.
+ * TODO and fix it properly in R / master: either deprecate this and have 3 APIs
+ * native + carrier + all, or have this return all by default.
* @throws UnsupportedOperationException if this subscription is not embedded.
* @hide
*/
@@ -595,8 +609,25 @@
if (!isEmbedded()) {
throw new UnsupportedOperationException("Not an embedded subscription");
}
- if (mAccessRules == null) return null;
- return Arrays.asList(mAccessRules);
+ if (mNativeAccessRules == null) return null;
+ return Arrays.asList(mNativeAccessRules);
+ }
+
+ /**
+ * @return the {@link UiccAccessRule}s that are both stored on Uicc and in carrierConfigs
+ * dictating who is authorized to manage this subscription.
+ * @hide
+ */
+ public @Nullable List<UiccAccessRule> getAllAccessRules() {
+ if (!isEmbedded()) {
+ throw new UnsupportedOperationException("Not an embedded subscription");
+ }
+ List<UiccAccessRule> merged = new ArrayList<>();
+ if (mNativeAccessRules != null) merged.addAll(getAccessRules());
+ if (mCarrierConfigAccessRules != null) {
+ merged.addAll(Arrays.asList(mCarrierConfigAccessRules));
+ }
+ return merged.isEmpty() ? null : merged;
}
/**
@@ -651,7 +682,7 @@
String countryIso = source.readString();
Bitmap iconBitmap = source.readParcelable(Bitmap.class.getClassLoader());
boolean isEmbedded = source.readBoolean();
- UiccAccessRule[] accessRules = source.createTypedArray(UiccAccessRule.CREATOR);
+ UiccAccessRule[] nativeAccessRules = source.createTypedArray(UiccAccessRule.CREATOR);
String cardString = source.readString();
int cardId = source.readInt();
boolean isOpportunistic = source.readBoolean();
@@ -663,11 +694,14 @@
String[] ehplmns = source.readStringArray();
String[] hplmns = source.readStringArray();
String groupOwner = source.readString();
+ UiccAccessRule[] carrierConfigAccessRules = source.createTypedArray(
+ UiccAccessRule.CREATOR);
SubscriptionInfo info = new SubscriptionInfo(id, iccId, simSlotIndex, displayName,
carrierName, nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc,
- countryIso, isEmbedded, accessRules, cardString, cardId, isOpportunistic,
- groupUUID, isGroupDisabled, carrierid, profileClass, subType, groupOwner);
+ countryIso, isEmbedded, nativeAccessRules, cardString, cardId, isOpportunistic,
+ groupUUID, isGroupDisabled, carrierid, profileClass, subType, groupOwner,
+ carrierConfigAccessRules);
info.setAssociatedPlmns(ehplmns, hplmns);
return info;
}
@@ -694,7 +728,7 @@
dest.writeString(mCountryIso);
dest.writeParcelable(mIconBitmap, flags);
dest.writeBoolean(mIsEmbedded);
- dest.writeTypedArray(mAccessRules, flags);
+ dest.writeTypedArray(mNativeAccessRules, flags);
dest.writeString(mCardString);
dest.writeInt(mCardId);
dest.writeBoolean(mIsOpportunistic);
@@ -706,6 +740,7 @@
dest.writeStringArray(mEhplmns);
dest.writeStringArray(mHplmns);
dest.writeString(mGroupOwner);
+ dest.writeTypedArray(mCarrierConfigAccessRules, flags);
}
@Override
@@ -736,9 +771,9 @@
+ " carrierId=" + mCarrierId + " displayName=" + mDisplayName
+ " carrierName=" + mCarrierName + " nameSource=" + mNameSource
+ " iconTint=" + mIconTint + " mNumber=" + Rlog.pii(Build.IS_DEBUGGABLE, mNumber)
- + " dataRoaming=" + mDataRoaming + " iconBitmap=" + mIconBitmap + " mcc=" + mMcc
- + " mnc=" + mMnc + " mCountryIso=" + mCountryIso + " isEmbedded=" + mIsEmbedded
- + " accessRules=" + Arrays.toString(mAccessRules)
+ + " dataRoaming=" + mDataRoaming + " iconBitmap=" + mIconBitmap + " mcc " + mMcc
+ + " mnc " + mMnc + "mCountryIso=" + mCountryIso + " isEmbedded " + mIsEmbedded
+ + " nativeAccessRules " + Arrays.toString(mNativeAccessRules)
+ " cardString=" + cardStringToPrint + " cardId=" + mCardId
+ " isOpportunistic=" + mIsOpportunistic + " mGroupUUID=" + mGroupUUID
+ " mIsGroupDisabled=" + mIsGroupDisabled
@@ -746,14 +781,15 @@
+ " ehplmns=" + Arrays.toString(mEhplmns)
+ " hplmns=" + Arrays.toString(mHplmns)
+ " subscriptionType=" + mSubscriptionType
- + " mGroupOwner=" + mGroupOwner + "}";
+ + " mGroupOwner=" + mGroupOwner
+ + " carrierConfigAccessRules=" + mCarrierConfigAccessRules + "}";
}
@Override
public int hashCode() {
return Objects.hash(mId, mSimSlotIndex, mNameSource, mIconTint, mDataRoaming, mIsEmbedded,
mIsOpportunistic, mGroupUUID, mIccId, mNumber, mMcc, mMnc,
- mCountryIso, mCardString, mCardId, mDisplayName, mCarrierName, mAccessRules,
+ mCountryIso, mCardString, mCardId, mDisplayName, mCarrierName, mNativeAccessRules,
mIsGroupDisabled, mCarrierId, mProfileClass, mGroupOwner);
}
@@ -789,7 +825,7 @@
&& Objects.equals(mGroupOwner, toCompare.mGroupOwner)
&& TextUtils.equals(mDisplayName, toCompare.mDisplayName)
&& TextUtils.equals(mCarrierName, toCompare.mCarrierName)
- && Arrays.equals(mAccessRules, toCompare.mAccessRules)
+ && Arrays.equals(mNativeAccessRules, toCompare.mNativeAccessRules)
&& mProfileClass == toCompare.mProfileClass
&& Arrays.equals(mEhplmns, toCompare.mEhplmns)
&& Arrays.equals(mHplmns, toCompare.mHplmns);
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 8c53c51..a84c916 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -571,6 +571,16 @@
public static final String ACCESS_RULES = "access_rules";
/**
+ * TelephonyProvider column name for the encoded {@link UiccAccessRule}s from
+ * {@link UiccAccessRule#encodeRules} but for the rules that come from CarrierConfigs.
+ * Only present if there are access rules in CarrierConfigs
+ * <p>TYPE: BLOB
+ * @hide
+ */
+ public static final String ACCESS_RULES_FROM_CARRIER_CONFIGS =
+ "access_rules_from_carrier_configs";
+
+ /**
* TelephonyProvider column name identifying whether an embedded subscription is on a removable
* card. Such subscriptions are marked inaccessible as soon as the current card is removed.
* Otherwise, they will remain accessible unless explicitly deleted. Only present if
@@ -2601,7 +2611,7 @@
if (!info.isEmbedded()) {
throw new IllegalArgumentException("Not an embedded subscription");
}
- if (info.getAccessRules() == null) {
+ if (info.getAllAccessRules() == null) {
return false;
}
PackageManager packageManager = mContext.getPackageManager();
@@ -2611,7 +2621,7 @@
} catch (PackageManager.NameNotFoundException e) {
throw new IllegalArgumentException("Unknown package: " + packageName, e);
}
- for (UiccAccessRule rule : info.getAccessRules()) {
+ for (UiccAccessRule rule : info.getAllAccessRules()) {
if (rule.getCarrierPrivilegeStatus(packageInfo)
== TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
return true;
diff --git a/telephony/java/android/telephony/data/DataServiceCallback.java b/telephony/java/android/telephony/data/DataServiceCallback.java
index 5d8d793..89d30c0d 100644
--- a/telephony/java/android/telephony/data/DataServiceCallback.java
+++ b/telephony/java/android/telephony/data/DataServiceCallback.java
@@ -42,6 +42,8 @@
private static final String TAG = DataServiceCallback.class.getSimpleName();
+ private static final boolean DBG = true;
+
/**
* Result of data requests
* @hide
@@ -81,6 +83,7 @@
IDataServiceCallback callback = mCallback.get();
if (callback != null) {
try {
+ if (DBG) Rlog.d(TAG, "onSetupDataCallComplete");
callback.onSetupDataCallComplete(result, response);
} catch (RemoteException e) {
Rlog.e(TAG, "Failed to onSetupDataCallComplete on the remote");
@@ -98,6 +101,7 @@
IDataServiceCallback callback = mCallback.get();
if (callback != null) {
try {
+ if (DBG) Rlog.d(TAG, "onDeactivateDataCallComplete");
callback.onDeactivateDataCallComplete(result);
} catch (RemoteException e) {
Rlog.e(TAG, "Failed to onDeactivateDataCallComplete on the remote");
@@ -169,6 +173,7 @@
IDataServiceCallback callback = mCallback.get();
if (callback != null) {
try {
+ if (DBG) Rlog.d(TAG, "onDataCallListChanged");
callback.onDataCallListChanged(dataCallList);
} catch (RemoteException e) {
Rlog.e(TAG, "Failed to onDataCallListChanged on the remote");
diff --git a/telephony/java/android/telephony/ims/ImsException.java b/telephony/java/android/telephony/ims/ImsException.java
index 8e1324b..6187e67 100644
--- a/telephony/java/android/telephony/ims/ImsException.java
+++ b/telephony/java/android/telephony/ims/ImsException.java
@@ -39,11 +39,11 @@
*/
public static final int CODE_ERROR_UNSPECIFIED = 0;
/**
- * The operation has failed because there is no {@link ImsService} available to service it. This
- * may be due to an {@link ImsService} crash or other illegal state.
+ * The operation has failed because there is no remote process available to service it. This
+ * may be due to a process crash or other illegal state.
* <p>
* This is a temporary error and the operation may be retried until the connection to the
- * {@link ImsService} is restored.
+ * remote process is restored.
*/
public static final int CODE_ERROR_SERVICE_UNAVAILABLE = 1;
diff --git a/telephony/java/android/telephony/ims/aidl/IImsRcsFeature.aidl b/telephony/java/android/telephony/ims/aidl/IImsRcsFeature.aidl
index 691cfba..4b98b79 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsRcsFeature.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsRcsFeature.aidl
@@ -16,10 +16,38 @@
package android.telephony.ims.aidl;
+import android.net.Uri;
+import android.telephony.ims.RcsContactUceCapability;
+import android.telephony.ims.aidl.IImsCapabilityCallback;
+import android.telephony.ims.aidl.IRcsFeatureListener;
+import android.telephony.ims.feature.CapabilityChangeRequest;
+
+import java.util.List;
+
/**
* See RcsFeature for more information.
* {@hide}
*/
interface IImsRcsFeature {
- //Empty Default Implementation
+ // Not oneway because we need to verify this completes before doing anything else.
+ void setListener(IRcsFeatureListener listener);
+ int queryCapabilityStatus();
+ // Inherited from ImsFeature
+ int getFeatureState();
+ oneway void addCapabilityCallback(IImsCapabilityCallback c);
+ oneway void removeCapabilityCallback(IImsCapabilityCallback c);
+ oneway void changeCapabilitiesConfiguration(in CapabilityChangeRequest r,
+ IImsCapabilityCallback c);
+ oneway void queryCapabilityConfiguration(int capability, int radioTech,
+ IImsCapabilityCallback c);
+ // RcsPresenceExchangeImplBase specific api
+ oneway void requestCapabilities(in List<Uri> uris, int operationToken);
+ oneway void updateCapabilities(in RcsContactUceCapability capabilities, int operationToken);
+ // RcsSipOptionsImplBase specific api
+ oneway void sendCapabilityRequest(in Uri contactUri,
+ in RcsContactUceCapability capabilities, int operationToken);
+ oneway void respondToCapabilityRequest(in String contactUri,
+ in RcsContactUceCapability ownCapabilities, int operationToken);
+ oneway void respondToCapabilityRequestWithError(in Uri contactUri, int code, in String reason,
+ int operationToken);
}
\ No newline at end of file
diff --git a/telephony/java/android/telephony/ims/aidl/IRcsFeatureListener.aidl b/telephony/java/android/telephony/ims/aidl/IRcsFeatureListener.aidl
new file mode 100644
index 0000000..881b477
--- /dev/null
+++ b/telephony/java/android/telephony/ims/aidl/IRcsFeatureListener.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2018 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.telephony.ims.aidl;
+
+import android.net.Uri;
+import android.telephony.ims.RcsContactUceCapability;
+
+import java.util.List;
+
+/**
+ * Listener interface for updates from the RcsFeature back to the framework.
+ * {@hide}
+ */
+interface IRcsFeatureListener {
+ //RcsCapabilityExchange specific
+ oneway void onCommandUpdate(int commandCode, int operationToken);
+ // RcsPresenceExchangeImplBase Specific
+ oneway void onNetworkResponse(int code, in String reason, int operationToken);
+ oneway void onCapabilityRequestResponsePresence(in List<RcsContactUceCapability> infos,
+ int operationToken);
+ oneway void onNotifyUpdateCapabilities();
+ oneway void onUnpublish();
+ // RcsSipOptionsImplBase specific
+ oneway void onCapabilityRequestResponseOptions(int code, in String reason,
+ in RcsContactUceCapability info, int operationToken);
+ oneway void onRemoteCapabilityRequest(in Uri contactUri, in RcsContactUceCapability remoteInfo,
+ int operationToken);
+}
\ No newline at end of file
diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java
index 8f89899..3a9979d 100644
--- a/telephony/java/android/telephony/ims/feature/ImsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java
@@ -33,12 +33,8 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.util.Collections;
import java.util.HashMap;
-import java.util.Iterator;
import java.util.Map;
-import java.util.Set;
-import java.util.WeakHashMap;
/**
* Base class for all IMS features that are supported by the framework. Use a concrete subclass
@@ -52,35 +48,6 @@
private static final String LOG_TAG = "ImsFeature";
/**
- * Action to broadcast when ImsService is up.
- * Internal use only.
- * Only defined here separately for compatibility purposes with the old ImsService.
- *
- * @hide
- */
- public static final String ACTION_IMS_SERVICE_UP =
- "com.android.ims.IMS_SERVICE_UP";
-
- /**
- * Action to broadcast when ImsService is down.
- * Internal use only.
- * Only defined here separately for compatibility purposes with the old ImsService.
- *
- * @hide
- */
- public static final String ACTION_IMS_SERVICE_DOWN =
- "com.android.ims.IMS_SERVICE_DOWN";
-
- /**
- * Part of the ACTION_IMS_SERVICE_UP or _DOWN intents.
- * A long value; the phone ID corresponding to the IMS service coming up or down.
- * Only defined here separately for compatibility purposes with the old ImsService.
- *
- * @hide
- */
- public static final String EXTRA_PHONE_ID = "android:phone_id";
-
- /**
* Invalid feature value
* @hide
*/
@@ -335,8 +302,8 @@
/** @hide */
protected final Object mLock = new Object();
- private final Set<IImsFeatureStatusCallback> mStatusCallbacks =
- Collections.newSetFromMap(new WeakHashMap<>());
+ private final RemoteCallbackList<IImsFeatureStatusCallback> mStatusCallbacks =
+ new RemoteCallbackList<>();
private @ImsState int mState = STATE_UNAVAILABLE;
private int mSlotId = SubscriptionManager.INVALID_SIM_SLOT_INDEX;
private final RemoteCallbackList<IImsCapabilityCallback> mCapabilityCallbacks =
@@ -397,9 +364,7 @@
// If we have just connected, send queued status.
c.notifyImsFeatureStatus(getFeatureState());
// Add the callback if the callback completes successfully without a RemoteException.
- synchronized (mLock) {
- mStatusCallbacks.add(c);
- }
+ mStatusCallbacks.register(c);
} catch (RemoteException e) {
Log.w(LOG_TAG, "Couldn't notify feature state: " + e.getMessage());
}
@@ -411,29 +376,21 @@
*/
@VisibleForTesting
public void removeImsFeatureStatusCallback(@NonNull IImsFeatureStatusCallback c) {
- synchronized (mLock) {
- mStatusCallbacks.remove(c);
- }
+ mStatusCallbacks.unregister(c);
}
/**
* Internal method called by ImsFeature when setFeatureState has changed.
*/
private void notifyFeatureState(@ImsState int state) {
- synchronized (mLock) {
- for (Iterator<IImsFeatureStatusCallback> iter = mStatusCallbacks.iterator();
- iter.hasNext(); ) {
- IImsFeatureStatusCallback callback = iter.next();
- try {
- Log.i(LOG_TAG, "notifying ImsFeatureState=" + state);
- callback.notifyImsFeatureStatus(state);
- } catch (RemoteException e) {
- // remove if the callback is no longer alive.
- iter.remove();
- Log.w(LOG_TAG, "Couldn't notify feature state: " + e.getMessage());
- }
+ mStatusCallbacks.broadcast((c) -> {
+ try {
+ c.notifyImsFeatureStatus(state);
+ } catch (RemoteException e) {
+ Log.w(LOG_TAG, e + " notifyFeatureState() - Skipping "
+ + "callback.");
}
- }
+ });
}
/**
@@ -452,10 +409,23 @@
/**
* @hide
*/
- public final void removeCapabilityCallback(IImsCapabilityCallback c) {
+ final void removeCapabilityCallback(IImsCapabilityCallback c) {
mCapabilityCallbacks.unregister(c);
}
+ /**@hide*/
+ final void queryCapabilityConfigurationInternal(int capability, int radioTech,
+ IImsCapabilityCallback c) {
+ boolean enabled = queryCapabilityConfiguration(capability, radioTech);
+ try {
+ if (c != null) {
+ c.onQueryCapabilityConfiguration(capability, radioTech, enabled);
+ }
+ } catch (RemoteException e) {
+ Log.e(LOG_TAG, "queryCapabilityConfigurationInternal called on dead binder!");
+ }
+ }
+
/**
* @return the cached capabilities status for this feature.
* @hide
@@ -484,31 +454,36 @@
/**
* Called by the ImsFeature when the capabilities status has changed.
*
- * @param c A {@link Capabilities} containing the new Capabilities status.
+ * @param caps the new {@link Capabilities} status of the {@link ImsFeature}.
*
* @hide
*/
- protected final void notifyCapabilitiesStatusChanged(Capabilities c) {
+ protected final void notifyCapabilitiesStatusChanged(Capabilities caps) {
synchronized (mLock) {
- mCapabilityStatus = c.copy();
+ mCapabilityStatus = caps.copy();
}
- int count = mCapabilityCallbacks.beginBroadcast();
- try {
- for (int i = 0; i < count; i++) {
- try {
- mCapabilityCallbacks.getBroadcastItem(i).onCapabilitiesStatusChanged(
- c.mCapabilities);
- } catch (RemoteException e) {
- Log.w(LOG_TAG, e + " " + "notifyCapabilitiesStatusChanged() - Skipping " +
- "callback.");
- }
+ mCapabilityCallbacks.broadcast((callback) -> {
+ try {
+ callback.onCapabilitiesStatusChanged(caps.mCapabilities);
+ } catch (RemoteException e) {
+ Log.w(LOG_TAG, e + " notifyCapabilitiesStatusChanged() - Skipping "
+ + "callback.");
}
- } finally {
- mCapabilityCallbacks.finishBroadcast();
- }
+ });
}
/**
+ * Provides the ImsFeature with the ability to return the framework Capability Configuration
+ * for a provided Capability. If the framework calls {@link #changeEnabledCapabilities} and
+ * includes a capability A to enable or disable, this method should return the correct enabled
+ * status for capability A.
+ * @param capability The capability that we are querying the configuration for.
+ * @return true if the capability is enabled, false otherwise.
+ * @hide
+ */
+ public abstract boolean queryCapabilityConfiguration(int capability, int radioTech);
+
+ /**
* Features should override this method to receive Capability preference change requests from
* the framework using the provided {@link CapabilityChangeRequest}. If any of the capabilities
* in the {@link CapabilityChangeRequest} are not able to be completed due to an error,
diff --git a/telephony/java/android/telephony/ims/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
index 898ca48..056a0ab 100644
--- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java
+++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
@@ -37,7 +37,6 @@
import android.telephony.ims.stub.ImsRegistrationImplBase;
import android.telephony.ims.stub.ImsSmsImplBase;
import android.telephony.ims.stub.ImsUtImplBase;
-import android.util.Log;
import com.android.ims.internal.IImsCallSession;
import com.android.ims.internal.IImsEcbm;
@@ -154,17 +153,13 @@
@Override
public void changeCapabilitiesConfiguration(CapabilityChangeRequest request,
IImsCapabilityCallback c) {
- synchronized (mLock) {
- MmTelFeature.this.requestChangeEnabledCapabilities(request, c);
- }
+ MmTelFeature.this.requestChangeEnabledCapabilities(request, c);
}
@Override
public void queryCapabilityConfiguration(int capability, int radioTech,
IImsCapabilityCallback c) {
- synchronized (mLock) {
- queryCapabilityConfigurationInternal(capability, radioTech, c);
- }
+ queryCapabilityConfigurationInternal(capability, radioTech, c);
}
@Override
@@ -381,18 +376,6 @@
}
}
- private void queryCapabilityConfigurationInternal(int capability, int radioTech,
- IImsCapabilityCallback c) {
- boolean enabled = queryCapabilityConfiguration(capability, radioTech);
- try {
- if (c != null) {
- c.onQueryCapabilityConfiguration(capability, radioTech, enabled);
- }
- } catch (RemoteException e) {
- Log.e(LOG_TAG, "queryCapabilityConfigurationInternal called on dead binder!");
- }
- }
-
/**
* The current capability status that this MmTelFeature has defined is available. This
* configuration will be used by the platform to figure out which capabilities are CURRENTLY
@@ -512,6 +495,7 @@
* @param capability The capability that we are querying the configuration for.
* @return true if the capability is enabled, false otherwise.
*/
+ @Override
public boolean queryCapabilityConfiguration(@MmTelCapabilities.MmTelCapability int capability,
@ImsRegistrationImplBase.ImsRegistrationTech int radioTech) {
// Base implementation - Override to provide functionality
diff --git a/telephony/java/android/telephony/ims/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java
index 5fae3ee..f69b434 100644
--- a/telephony/java/android/telephony/ims/feature/RcsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java
@@ -16,14 +16,32 @@
package android.telephony.ims.feature;
+import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.SystemApi;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.telephony.ims.RcsContactUceCapability;
+import android.telephony.ims.aidl.IImsCapabilityCallback;
import android.telephony.ims.aidl.IImsRcsFeature;
+import android.telephony.ims.aidl.IRcsFeatureListener;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
import android.telephony.ims.stub.RcsPresenceExchangeImplBase;
import android.telephony.ims.stub.RcsSipOptionsImplBase;
+import android.util.Log;
+
+import com.android.internal.util.FunctionalUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
/**
* Base implementation of the RcsFeature APIs. Any ImsService wishing to support RCS should extend
@@ -33,10 +51,132 @@
@SystemApi
public class RcsFeature extends ImsFeature {
- /**{@inheritDoc}*/
- private final IImsRcsFeature mImsRcsBinder = new IImsRcsFeature.Stub() {
- // Empty Default Implementation.
- };
+ private static final String LOG_TAG = "RcsFeature";
+
+ private static final class RcsFeatureBinder extends IImsRcsFeature.Stub {
+ // Reference the outer class in order to have better test coverage metrics instead of
+ // creating a inner class referencing the outer class directly.
+ private final RcsFeature mReference;
+ private final Executor mExecutor;
+
+ RcsFeatureBinder(RcsFeature classRef, @CallbackExecutor Executor executor) {
+ mReference = classRef;
+ mExecutor = executor;
+ }
+
+ @Override
+ public void setListener(IRcsFeatureListener listener) {
+ mReference.setListener(listener);
+ }
+
+ @Override
+ public int queryCapabilityStatus() throws RemoteException {
+ return executeMethodAsyncForResult(
+ () -> mReference.queryCapabilityStatus().mCapabilities,
+ "queryCapabilityStatus");
+ }
+
+ @Override
+ public void addCapabilityCallback(IImsCapabilityCallback c) throws RemoteException {
+ executeMethodAsync(() -> mReference.addCapabilityCallback(c), "addCapabilityCallback");
+ }
+
+ @Override
+ public void removeCapabilityCallback(IImsCapabilityCallback c) throws RemoteException {
+ executeMethodAsync(() -> mReference.removeCapabilityCallback(c),
+ "removeCapabilityCallback");
+ }
+
+ @Override
+ public void changeCapabilitiesConfiguration(CapabilityChangeRequest r,
+ IImsCapabilityCallback c) throws RemoteException {
+ executeMethodAsync(() -> mReference.requestChangeEnabledCapabilities(r, c),
+ "changeCapabilitiesConfiguration");
+ }
+
+ @Override
+ public void queryCapabilityConfiguration(int capability, int radioTech,
+ IImsCapabilityCallback c) throws RemoteException {
+ executeMethodAsync(() -> mReference.queryCapabilityConfigurationInternal(capability,
+ radioTech, c), "queryCapabilityConfiguration");
+ }
+
+ @Override
+ public int getFeatureState() throws RemoteException {
+ return executeMethodAsyncForResult(mReference::getFeatureState, "getFeatureState");
+ }
+
+ // RcsPresenceExchangeImplBase specific APIS
+ @Override
+ public void requestCapabilities(List<Uri> uris, int operationToken) throws RemoteException {
+ executeMethodAsync(() -> mReference.getPresenceExchangeInternal()
+ .requestCapabilities(uris, operationToken), "requestCapabilities");
+ }
+ @Override
+ public void updateCapabilities(RcsContactUceCapability capabilities, int operationToken)
+ throws RemoteException {
+ executeMethodAsync(() -> mReference.getPresenceExchangeInternal()
+ .updateCapabilities(capabilities, operationToken),
+ "updateCapabilities");
+
+ }
+ // RcsSipOptionsImplBase specific APIS
+ @Override
+ public void sendCapabilityRequest(Uri contactUri, RcsContactUceCapability capabilities,
+ int operationToken) throws RemoteException {
+ executeMethodAsync(() -> mReference.getOptionsExchangeInternal()
+ .sendCapabilityRequest(contactUri, capabilities, operationToken),
+ "sendCapabilityRequest");
+
+ }
+ @Override
+ public void respondToCapabilityRequest(String contactUri,
+ RcsContactUceCapability ownCapabilities, int operationToken)
+ throws RemoteException {
+ executeMethodAsync(() -> mReference.getOptionsExchangeInternal()
+ .respondToCapabilityRequest(contactUri, ownCapabilities,
+ operationToken), "respondToCapabilityRequest");
+
+ }
+ @Override
+ public void respondToCapabilityRequestWithError(Uri contactUri, int code, String reason,
+ int operationToken) throws RemoteException {
+ executeMethodAsync(() -> mReference.getOptionsExchangeInternal()
+ .respondToCapabilityRequestWithError(contactUri, code, reason,
+ operationToken), "respondToCapabilityRequestWithError");
+ }
+
+ // Call the methods with a clean calling identity on the executor and wait indefinitely for
+ // the future to return.
+ private void executeMethodAsync(FunctionalUtils.ThrowingRunnable r, String errorLogName)
+ throws RemoteException {
+ // call with a clean calling identity on the executor and wait indefinitely for the
+ // future to return.
+ try {
+ CompletableFuture.runAsync(
+ () -> Binder.withCleanCallingIdentity(r), mExecutor).join();
+ } catch (CancellationException | CompletionException e) {
+ Log.w(LOG_TAG, "RcsFeatureBinder - " + errorLogName + " exception: "
+ + e.getMessage());
+ throw new RemoteException(e.getMessage());
+ }
+ }
+
+ private <T> T executeMethodAsyncForResult(FunctionalUtils.ThrowingSupplier<T> r,
+ String errorLogName) throws RemoteException {
+ // call with a clean calling identity on the executor and wait indefinitely for the
+ // future to return.
+ CompletableFuture<T> future = CompletableFuture.supplyAsync(
+ () -> Binder.withCleanCallingIdentity(r), mExecutor);
+ try {
+ return future.get();
+ } catch (ExecutionException | InterruptedException e) {
+ Log.w(LOG_TAG, "RcsFeatureBinder - " + errorLogName + " exception: "
+ + e.getMessage());
+ throw new RemoteException(e.getMessage());
+ }
+ }
+ }
/**
* Contains the capabilities defined and supported by a {@link RcsFeature} in the
@@ -81,27 +221,66 @@
/**@hide*/
public RcsImsCapabilities(@RcsImsCapabilityFlag int capabilities) {
+ super(capabilities);
+ }
+ /**@hide*/
+ private RcsImsCapabilities(Capabilities c) {
+ super(c.getMask());
}
/**@hide*/
@Override
public void addCapabilities(@RcsImsCapabilityFlag int capabilities) {
-
+ super.addCapabilities(capabilities);
}
/**@hide*/
@Override
public void removeCapabilities(@RcsImsCapabilityFlag int capabilities) {
-
+ super.removeCapabilities(capabilities);
}
/**@hide*/
@Override
public boolean isCapable(@RcsImsCapabilityFlag int capabilities) {
- return false;
+ return super.isCapable(capabilities);
}
}
+
+ private final RcsFeatureBinder mImsRcsBinder;
+ private IRcsFeatureListener mListenerBinder;
+ private RcsPresenceExchangeImplBase mPresExchange;
+ private RcsSipOptionsImplBase mSipOptions;
+
+ /**
+ * Create a new RcsFeature.
+ * <p>
+ * Method stubs called from the framework will be called asynchronously. To specify the
+ * {@link Executor} that the methods stubs will be called, use
+ * {@link RcsFeature#RcsFeature(Executor)} instead.
+ */
+ public RcsFeature() {
+ super();
+ // Run on the Binder threads that call them.
+ mImsRcsBinder = new RcsFeatureBinder(this, Runnable::run);
+ }
+
+ /**
+ * Create a new RcsFeature using the Executor specified for methods being called by the
+ * framework.
+ * @param executor The executor for the framework to use when making calls to this service.
+ * @hide
+ */
+ public RcsFeature(@NonNull Executor executor) {
+ super();
+ if (executor == null) {
+ throw new IllegalArgumentException("executor can not be null.");
+ }
+ // Run on the Binder thread by default.
+ mImsRcsBinder = new RcsFeatureBinder(this, executor);
+ }
+
/**
* Query the current {@link RcsImsCapabilities} status set by the RcsFeature. If a capability is
* set, the {@link RcsFeature} has brought up the capability and is ready for framework
@@ -111,7 +290,7 @@
*/
@Override
public final RcsImsCapabilities queryCapabilityStatus() {
- throw new UnsupportedOperationException();
+ return new RcsImsCapabilities(super.queryCapabilityStatus());
}
/**
@@ -120,8 +299,11 @@
* Call {@link #queryCapabilityStatus()} to return the current capability status.
* @hide
*/
- public final void notifyCapabilitiesStatusChanged(RcsImsCapabilities c) {
- throw new UnsupportedOperationException();
+ public final void notifyCapabilitiesStatusChanged(@NonNull RcsImsCapabilities c) {
+ if (c == null) {
+ throw new IllegalArgumentException("RcsImsCapabilities must be non-null!");
+ }
+ super.notifyCapabilitiesStatusChanged(c);
}
/**
@@ -133,8 +315,10 @@
* @hide
*/
public boolean queryCapabilityConfiguration(
- @RcsImsCapabilities.RcsImsCapabilityFlag int capability) {
- throw new UnsupportedOperationException();
+ @RcsImsCapabilities.RcsImsCapabilityFlag int capability,
+ @ImsRegistrationImplBase.ImsRegistrationTech int radioTech) {
+ // Base Implementation - Override to provide functionality
+ return false;
}
/**
* Called from the framework when the {@link RcsImsCapabilities} that have been configured for
@@ -155,7 +339,7 @@
@Override
public void changeEnabledCapabilities(CapabilityChangeRequest request,
CapabilityCallbackProxy c) {
- throw new UnsupportedOperationException();
+ // Base Implementation - Override to provide functionality
}
/**
@@ -192,13 +376,6 @@
return new RcsPresenceExchangeImplBase();
}
- /**
- * Construct a new {@link RcsFeature} instance.
- */
- public RcsFeature() {
- super();
- }
-
/**{@inheritDoc}*/
@Override
public void onFeatureRemoved() {
@@ -218,4 +395,40 @@
public final IImsRcsFeature getBinder() {
return mImsRcsBinder;
}
+
+ /**@hide*/
+ public IRcsFeatureListener getListener() {
+ synchronized (mLock) {
+ return mListenerBinder;
+ }
+ }
+
+ private void setListener(IRcsFeatureListener listener) {
+ synchronized (mLock) {
+ mListenerBinder = listener;
+ if (mListenerBinder != null) {
+ onFeatureReady();
+ }
+ }
+ }
+
+ private RcsPresenceExchangeImplBase getPresenceExchangeInternal() {
+ synchronized (mLock) {
+ if (mPresExchange == null) {
+ mPresExchange = getPresenceExchangeImpl();
+ mPresExchange.initialize(this);
+ }
+ return mPresExchange;
+ }
+ }
+
+ private RcsSipOptionsImplBase getOptionsExchangeInternal() {
+ synchronized (mLock) {
+ if (mSipOptions == null) {
+ mSipOptions = getOptionsExchangeImpl();
+ mSipOptions.initialize(this);
+ }
+ return mSipOptions;
+ }
+ }
}
diff --git a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java
index 289fd4c..fda295a 100644
--- a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java
+++ b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java
@@ -17,6 +17,11 @@
package android.telephony.ims.stub;
import android.annotation.IntDef;
+import android.os.RemoteException;
+import android.telephony.ims.ImsException;
+import android.telephony.ims.aidl.IRcsFeatureListener;
+import android.telephony.ims.feature.ImsFeature;
+import android.telephony.ims.feature.RcsFeature;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -72,6 +77,24 @@
})
public @interface CommandCode {}
+
+ private RcsFeature mFeature;
+
+ /** @hide */
+ public final void initialize(RcsFeature feature) {
+ mFeature = feature;
+ }
+
+ /** @hide */
+ protected final IRcsFeatureListener getListener() throws ImsException {
+ IRcsFeatureListener listener = mFeature.getListener();
+ if (listener == null) {
+ throw new ImsException("Connection to Framework has not been established, wait for "
+ + "onFeatureReady().", ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
+ return mFeature.getListener();
+ }
+
/**
* Provides the framework with an update as to whether or not a command completed successfully
* locally. This includes capabilities requests and updates from the network. If it does not
@@ -82,8 +105,18 @@
* @param code The result of the pending command. If {@link #COMMAND_CODE_SUCCESS}, further
* updates will be sent for this command using the associated operationToken.
* @param operationToken the token associated with the pending command.
+ * @throws ImsException If this {@link RcsCapabilityExchange} instance is not currently
+ * connected to the framework. This can happen if the {@link RcsFeature} is not
+ * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received the
+ * {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases when the
+ * Telephony stack has crashed.
*/
- public final void onCommandUpdate(@CommandCode int code, int operationToken) {
- throw new UnsupportedOperationException();
+ public final void onCommandUpdate(@CommandCode int code, int operationToken)
+ throws ImsException {
+ try {
+ getListener().onCommandUpdate(code, operationToken);
+ } catch (RemoteException e) {
+ throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
}
}
diff --git a/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java b/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java
index 4402470..055fca5 100644
--- a/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java
@@ -19,7 +19,11 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.net.Uri;
+import android.os.RemoteException;
+import android.telephony.ims.ImsException;
import android.telephony.ims.RcsContactUceCapability;
+import android.telephony.ims.feature.ImsFeature;
+import android.telephony.ims.feature.RcsFeature;
import android.util.Log;
import java.lang.annotation.Retention;
@@ -113,54 +117,95 @@
* Provide the framework with a subsequent network response update to
* {@link #updateCapabilities(RcsContactUceCapability, int)} and
* {@link #requestCapabilities(List, int)} operations.
+ *
* @param code The SIP response code sent from the network for the operation token specified.
* @param reason The optional reason response from the network. If the network provided no
* reason with the code, the string should be empty.
* @param operationToken The token associated with the operation this service is providing a
* response for.
+ * @throws ImsException If this {@link RcsPresenceExchangeImplBase} instance is not currently
+ * connected to the framework. This can happen if the {@link RcsFeature} is not
+ * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received the
+ * {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases when the
+ * Telephony stack has crashed.
*/
public final void onNetworkResponse(@PresenceResponseCode int code, @NonNull String reason,
- int operationToken) {
- throw new UnsupportedOperationException();
+ int operationToken) throws ImsException {
+ try {
+ getListener().onNetworkResponse(code, reason, operationToken);
+ } catch (RemoteException e) {
+ throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
}
/**
* Provides the framework with the requested contacts’ capabilities requested by the framework
- * using {@link #requestCapabilities(List, int)} .
+ * using {@link #requestCapabilities(List, int)}.
+ *
+ * @throws ImsException If this {@link RcsPresenceExchangeImplBase} instance is not currently
+ * connected to the framework. This can happen if the {@link RcsFeature} is not
+ * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received the
+ * {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases when the
+ * Telephony stack has crashed.
*/
public final void onCapabilityRequestResponse(@NonNull List<RcsContactUceCapability> infos,
- int operationToken) {
- throw new UnsupportedOperationException();
+ int operationToken) throws ImsException {
+ try {
+ getListener().onCapabilityRequestResponsePresence(infos, operationToken);
+ } catch (RemoteException e) {
+ throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
}
/**
* Trigger the framework to provide a capability update using
- * {@link #updateCapabilities(RcsContactUceCapability, int)}. This is typically used when trying
- * to generate an initial PUBLISH for a new subscription to the network.
+ * {@link #updateCapabilities(RcsContactUceCapability, int)}.
* <p>
- * The device will cache all presence publications after boot until this method is called once.
+ * This is typically used when trying to generate an initial PUBLISH for a new subscription to
+ * the network. The device will cache all presence publications after boot until this method is
+ * called once.
+ * @throws ImsException If this {@link RcsPresenceExchangeImplBase} instance is not currently
+ * connected to the framework. This can happen if the {@link RcsFeature} is not
+ * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received the
+ * {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases when the
+ * Telephony stack has crashed.
*/
- public final void onNotifyUpdateCapabilites() {
- throw new UnsupportedOperationException();
+ public final void onNotifyUpdateCapabilites() throws ImsException {
+ try {
+ getListener().onNotifyUpdateCapabilities();
+ } catch (RemoteException e) {
+ throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
}
/**
* Notify the framework that the device’s capabilities have been unpublished from the network.
+ *
+ * @throws ImsException If this {@link RcsPresenceExchangeImplBase} instance is not currently
+ * connected to the framework. This can happen if the {@link RcsFeature} is not
+ * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received the
+ * {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases when the
+ * Telephony stack has crashed.
*/
- public final void onUnpublish() {
- throw new UnsupportedOperationException();
+ public final void onUnpublish() throws ImsException {
+ try {
+ getListener().onUnpublish();
+ } catch (RemoteException e) {
+ throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
}
/**
- * The user capabilities of one or multiple contacts have been requested.
+ * The user capabilities of one or multiple contacts have been requested by the framework.
* <p>
- * This must be followed up with one call to {@link #onCommandUpdate(int, int)} with an update
- * as to whether or not the command completed as well as subsequent network
- * updates using {@link #onNetworkResponse(int, String, int)}. When the operation is completed,
- * {@link #onCapabilityRequestResponse(List, int)} should be called with
- * the presence information for the contacts specified.
- * @param uris A {@link List} of the URIs that the framework is requesting the UCE capabilities
- * for.
+ * The implementer must follow up this call with an {@link #onCommandUpdate(int, int)} call to
+ * indicate whether or not this operation succeeded. If this operation succeeds, network
+ * response updates should be sent to the framework using
+ * {@link #onNetworkResponse(int, String, int)}. When the operation is completed,
+ * {@link #onCapabilityRequestResponse(List, int)} should be called with the presence
+ * information for the contacts specified.
+ * @param uris A {@link List} of the {@link Uri}s that the framework is requesting the UCE
+ * capabilities for.
* @param operationToken The token associated with this operation. Updates to this request using
* {@link #onCommandUpdate(int, int)}, {@link #onNetworkResponse(int, String, int)}, and
* {@link #onCapabilityRequestResponse(List, int)} must use the same operation token
@@ -169,14 +214,20 @@
public void requestCapabilities(@NonNull List<Uri> uris, int operationToken) {
// Stub - to be implemented by service
Log.w(LOG_TAG, "requestCapabilities called with no implementation.");
- onCommandUpdate(COMMAND_CODE_GENERIC_FAILURE, operationToken);
+ try {
+ getListener().onCommandUpdate(COMMAND_CODE_NOT_SUPPORTED, operationToken);
+ } catch (RemoteException | ImsException e) {
+ // Do not do anything, this is a stub implementation.
+ }
}
/**
- * The capabilities of this device have been updated and should be published
- * to the network. The framework will expect one {@link #onCommandUpdate(int, int)} call to
- * indicate whether or not this operation failed first as well as network response
- * updates to this update using {@link #onNetworkResponse(int, String, int)}.
+ * The capabilities of this device have been updated and should be published to the network.
+ * <p>
+ * The implementer must follow up this call with an {@link #onCommandUpdate(int, int)} call to
+ * indicate whether or not this operation succeeded. If this operation succeeds, network
+ * response updates should be sent to the framework using
+ * {@link #onNetworkResponse(int, String, int)}.
* @param capabilities The capabilities for this device.
* @param operationToken The token associated with this operation. Any subsequent
* {@link #onCommandUpdate(int, int)} or {@link #onNetworkResponse(int, String, int)}
@@ -186,6 +237,10 @@
int operationToken) {
// Stub - to be implemented by service
Log.w(LOG_TAG, "updateCapabilities called with no implementation.");
- onCommandUpdate(COMMAND_CODE_GENERIC_FAILURE, operationToken);
+ try {
+ getListener().onCommandUpdate(COMMAND_CODE_NOT_SUPPORTED, operationToken);
+ } catch (RemoteException | ImsException e) {
+ // Do not do anything, this is a stub implementation.
+ }
}
}
diff --git a/telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java b/telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java
index 3343074..1c68fc0 100644
--- a/telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java
@@ -20,7 +20,11 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.net.Uri;
+import android.os.RemoteException;
+import android.telephony.ims.ImsException;
import android.telephony.ims.RcsContactUceCapability;
+import android.telephony.ims.feature.ImsFeature;
+import android.telephony.ims.feature.RcsFeature;
import android.util.Log;
import java.lang.annotation.Retention;
@@ -87,10 +91,19 @@
* @param info the contact's UCE capabilities associated with the capability request.
* @param operationToken The token associated with the original capability request, set by
* {@link #sendCapabilityRequest(Uri, RcsContactUceCapability, int)}.
+ * @throws ImsException If this {@link RcsSipOptionsImplBase} instance is not currently
+ * connected to the framework. This can happen if the {@link RcsFeature} is not
+ * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received the
+ * {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases when the
+ * Telephony stack has crashed.
*/
public final void onCapabilityRequestResponse(@SipResponseCode int code, @NonNull String reason,
- @Nullable RcsContactUceCapability info, int operationToken) {
- throw new UnsupportedOperationException();
+ @Nullable RcsContactUceCapability info, int operationToken) throws ImsException {
+ try {
+ getListener().onCapabilityRequestResponseOptions(code, reason, info, operationToken);
+ } catch (RemoteException e) {
+ throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
}
/**
@@ -104,10 +117,19 @@
* @param operationToken An unique operation token that you have generated that will be returned
* by the framework in
* {@link #respondToCapabilityRequest(String, RcsContactUceCapability, int)}.
+ * @throws ImsException If this {@link RcsSipOptionsImplBase} instance is not currently
+ * connected to the framework. This can happen if the {@link RcsFeature} is not
+ * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received the
+ * {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases when the
+ * Telephony stack has crashed.
*/
public final void onRemoteCapabilityRequest(@NonNull Uri contactUri,
- @NonNull RcsContactUceCapability remoteInfo, int operationToken) {
- throw new UnsupportedOperationException();
+ @NonNull RcsContactUceCapability remoteInfo, int operationToken) throws ImsException {
+ try {
+ getListener().onRemoteCapabilityRequest(contactUri, remoteInfo, operationToken);
+ } catch (RemoteException e) {
+ throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
}
/**
@@ -127,7 +149,11 @@
@NonNull RcsContactUceCapability capabilities, int operationToken) {
// Stub - to be implemented by service
Log.w(LOG_TAG, "sendCapabilityRequest called with no implementation.");
- onCommandUpdate(COMMAND_CODE_GENERIC_FAILURE, operationToken);
+ try {
+ getListener().onCommandUpdate(COMMAND_CODE_NOT_SUPPORTED, operationToken);
+ } catch (RemoteException | ImsException e) {
+ // Do not do anything, this is a stub implementation.
+ }
}
/**
@@ -145,7 +171,11 @@
@NonNull RcsContactUceCapability ownCapabilities, int operationToken) {
// Stub - to be implemented by service
Log.w(LOG_TAG, "respondToCapabilityRequest called with no implementation.");
- onCommandUpdate(COMMAND_CODE_GENERIC_FAILURE, operationToken);
+ try {
+ getListener().onCommandUpdate(COMMAND_CODE_NOT_SUPPORTED, operationToken);
+ } catch (RemoteException | ImsException e) {
+ // Do not do anything, this is a stub implementation.
+ }
}
/**
@@ -164,6 +194,10 @@
@SipResponseCode int code, @NonNull String reason, int operationToken) {
// Stub - to be implemented by service
Log.w(LOG_TAG, "respondToCapabiltyRequestWithError called with no implementation.");
- onCommandUpdate(COMMAND_CODE_GENERIC_FAILURE, operationToken);
+ try {
+ getListener().onCommandUpdate(COMMAND_CODE_NOT_SUPPORTED, operationToken);
+ } catch (RemoteException | ImsException e) {
+ // Do not do anything, this is a stub implementation.
+ }
}
}
diff --git a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
index e9a177d..4e1ff8f 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
@@ -32,9 +32,11 @@
import android.os.UserManager;
import android.provider.ContactsContract.PhoneLookup;
import android.telephony.PhoneNumberUtils;
-import android.text.TextUtils;
import android.telephony.Rlog;
import android.telephony.SubscriptionManager;
+import android.text.TextUtils;
+
+import dalvik.annotation.compat.UnsupportedAppUsage;
import java.util.ArrayList;
import java.util.List;
@@ -80,6 +82,10 @@
* classes.
*/
private static final class CookieWrapper {
+ @UnsupportedAppUsage
+ private CookieWrapper() {
+ }
+
public OnQueryCompleteListener listener;
public Object cookie;
public int event;
@@ -527,6 +533,7 @@
/**
* Releases the relevant data.
*/
+ @UnsupportedAppUsage
private void release() {
mHandler.mContext = null;
mHandler.mQueryUri = null;
diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java
index cde6db4..e1113eb 100644
--- a/telephony/java/com/android/internal/telephony/DctConstants.java
+++ b/telephony/java/com/android/internal/telephony/DctConstants.java
@@ -17,6 +17,8 @@
import com.android.internal.util.Protocol;
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
/**
* @hide
*/
@@ -37,20 +39,34 @@
* RETRYING or CONNECTING: CONNECTING
* CONNECTED : CONNECTED or DISCONNECTING
*/
+ @UnsupportedAppUsage(implicitMember =
+ "values()[Lcom/android/internal/telephony/DctConstants$State;")
public enum State {
+ @UnsupportedAppUsage
IDLE,
+ @UnsupportedAppUsage
CONNECTING,
+ @UnsupportedAppUsage
RETRYING,
+ @UnsupportedAppUsage
CONNECTED,
+ @UnsupportedAppUsage
DISCONNECTING,
+ @UnsupportedAppUsage
FAILED,
}
+ @UnsupportedAppUsage(implicitMember =
+ "values()[Lcom/android/internal/telephony/DctConstants$Activity;")
public enum Activity {
NONE,
+ @UnsupportedAppUsage
DATAIN,
+ @UnsupportedAppUsage
DATAOUT,
+ @UnsupportedAppUsage
DATAINANDOUT,
+ @UnsupportedAppUsage
DORMANT
}
diff --git a/telephony/java/com/android/internal/telephony/GsmAlphabet.java b/telephony/java/com/android/internal/telephony/GsmAlphabet.java
index a75096f..5fb4e90 100644
--- a/telephony/java/com/android/internal/telephony/GsmAlphabet.java
+++ b/telephony/java/com/android/internal/telephony/GsmAlphabet.java
@@ -16,19 +16,17 @@
package com.android.internal.telephony;
+import android.annotation.UnsupportedAppUsage;
import android.content.res.Resources;
+import android.os.Build;
+import android.telephony.Rlog;
import android.text.TextUtils;
import android.util.SparseIntArray;
-import android.annotation.UnsupportedAppUsage;
-import android.os.Build;
-import android.telephony.Rlog;
+import com.android.internal.R;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
-import com.android.internal.telephony.SmsConstants;
-import com.android.internal.R;
-
import java.util.ArrayList;
import java.util.List;
@@ -83,6 +81,11 @@
* data.
*/
public static class TextEncodingDetails {
+
+ @UnsupportedAppUsage
+ public TextEncodingDetails() {
+ }
+
/**
*The number of SMS's required to encode the text.
*/
diff --git a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
index 5b509b7..15e7fc2 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
@@ -27,6 +27,7 @@
/**
* Retrieves the unique device ID, e.g., IMEI for GSM phones.
*/
+ @UnsupportedAppUsage
String getDeviceId(String callingPackage);
/**
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index a65acac..9f1a2f7 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -94,6 +94,7 @@
* @param callingPackage the name of the package making the call.
* @return returns true if the radio is on.
*/
+ @UnsupportedAppUsage
boolean isRadioOn(String callingPackage);
/**
@@ -1254,6 +1255,7 @@
* <p>Requires Permission:
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*/
+ @UnsupportedAppUsage
String getDeviceId(String callingPackage);
/**
diff --git a/telephony/java/com/android/internal/telephony/IccCardConstants.java b/telephony/java/com/android/internal/telephony/IccCardConstants.java
index d57f9af..6ff27b1 100644
--- a/telephony/java/com/android/internal/telephony/IccCardConstants.java
+++ b/telephony/java/com/android/internal/telephony/IccCardConstants.java
@@ -17,6 +17,8 @@
import android.telephony.TelephonyManager;
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
/**
* {@hide}
*/
@@ -65,15 +67,26 @@
*
* The ordinal values much match {@link TelephonyManager#SIM_STATE_UNKNOWN} ...
*/
+ @UnsupportedAppUsage(implicitMember =
+ "values()[Lcom/android/internal/telephony/IccCardConstants$State;")
public enum State {
+ @UnsupportedAppUsage
UNKNOWN, /** ordinal(0) == {@See TelephonyManager#SIM_STATE_UNKNOWN} */
+ @UnsupportedAppUsage
ABSENT, /** ordinal(1) == {@See TelephonyManager#SIM_STATE_ABSENT} */
+ @UnsupportedAppUsage
PIN_REQUIRED, /** ordinal(2) == {@See TelephonyManager#SIM_STATE_PIN_REQUIRED} */
+ @UnsupportedAppUsage
PUK_REQUIRED, /** ordinal(3) == {@See TelephonyManager#SIM_STATE_PUK_REQUIRED} */
+ @UnsupportedAppUsage
NETWORK_LOCKED, /** ordinal(4) == {@See TelephonyManager#SIM_STATE_NETWORK_LOCKED} */
+ @UnsupportedAppUsage
READY, /** ordinal(5) == {@See TelephonyManager#SIM_STATE_READY} */
+ @UnsupportedAppUsage
NOT_READY, /** ordinal(6) == {@See TelephonyManager#SIM_STATE_NOT_READY} */
+ @UnsupportedAppUsage
PERM_DISABLED, /** ordinal(7) == {@See TelephonyManager#SIM_STATE_PERM_DISABLED} */
+ @UnsupportedAppUsage
CARD_IO_ERROR, /** ordinal(8) == {@See TelephonyManager#SIM_STATE_CARD_IO_ERROR} */
CARD_RESTRICTED,/** ordinal(9) == {@See TelephonyManager#SIM_STATE_CARD_RESTRICTED} */
LOADED; /** ordinal(9) == {@See TelephonyManager#SIM_STATE_LOADED} */
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index d5061a3..ee1a476 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -15,6 +15,8 @@
*/
package com.android.internal.telephony;
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
/**
* @hide
*/
@@ -31,8 +33,12 @@
* ringing or waiting.</li>
* </ul>
*/
+ @UnsupportedAppUsage(implicitMember =
+ "values()[Lcom/android/internal/telephony/PhoneConstants$State;")
public enum State {
- IDLE, RINGING, OFFHOOK;
+ @UnsupportedAppUsage IDLE,
+ @UnsupportedAppUsage RINGING,
+ @UnsupportedAppUsage OFFHOOK;
};
/**
@@ -46,8 +52,13 @@
* in 2G network</li>
* </ul>
*/
+ @UnsupportedAppUsage(implicitMember =
+ "values()[Lcom/android/internal/telephony/PhoneConstants$DataState;")
public enum DataState {
- CONNECTED, CONNECTING, DISCONNECTED, SUSPENDED;
+ @UnsupportedAppUsage CONNECTED,
+ @UnsupportedAppUsage CONNECTING,
+ @UnsupportedAppUsage DISCONNECTED,
+ @UnsupportedAppUsage SUSPENDED;
};
public static final String STATE_KEY = "state";
@@ -69,9 +80,13 @@
public static final int LTE_ON_CDMA_TRUE = RILConstants.LTE_ON_CDMA_TRUE;
// Number presentation type for caller id display (From internal/Connection.java)
+ @UnsupportedAppUsage
public static final int PRESENTATION_ALLOWED = 1; // normal
+ @UnsupportedAppUsage
public static final int PRESENTATION_RESTRICTED = 2; // block by user
+ @UnsupportedAppUsage
public static final int PRESENTATION_UNKNOWN = 3; // no specified or unknown by network
+ @UnsupportedAppUsage
public static final int PRESENTATION_PAYPHONE = 4; // show pay phone info
// Sim activation type
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 5205973..03ea920 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -18,6 +18,8 @@
import android.telephony.TelephonyManager;
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
/**
* {@hide}
*/
@@ -230,6 +232,7 @@
/** NR 5G, LTE, TD-SCDMA, CDMA, EVDO, GSM and WCDMA */
int NETWORK_MODE_NR_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA = 33;
+ @UnsupportedAppUsage
int PREFERRED_NETWORK_MODE = Integer.parseInt(TelephonyManager.getTelephonyProperty(0,
"ro.telephony.default_network", Integer.toString(NETWORK_MODE_WCDMA_PREF)));
diff --git a/telephony/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java b/telephony/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java
index 49c737f..2cdf2f6 100644
--- a/telephony/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java
+++ b/telephony/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java
@@ -16,27 +16,28 @@
package com.android.internal.telephony;
-import android.telephony.Rlog;
-import android.os.Build;
-import android.util.SparseIntArray;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
-import android.telephony.SmsManager;
-import android.telephony.TelephonyManager;
+import android.os.Build;
+import android.telephony.Rlog;
+import android.util.SparseIntArray;
-import com.android.internal.util.XmlUtils;
import com.android.internal.telephony.cdma.sms.UserData;
+import com.android.internal.util.XmlUtils;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
+import dalvik.annotation.compat.UnsupportedAppUsage;
public class Sms7BitEncodingTranslator {
private static final String TAG = "Sms7BitEncodingTranslator";
+ @UnsupportedAppUsage
private static final boolean DBG = Build.IS_DEBUGGABLE ;
private static boolean mIs7BitTranslationTableLoaded = false;
private static SparseIntArray mTranslationTable = null;
+ @UnsupportedAppUsage
private static SparseIntArray mTranslationTableCommon = null;
+ @UnsupportedAppUsage
private static SparseIntArray mTranslationTableGSM = null;
+ @UnsupportedAppUsage
private static SparseIntArray mTranslationTableCDMA = null;
// Parser variables
diff --git a/telephony/java/com/android/internal/telephony/SmsApplication.java b/telephony/java/com/android/internal/telephony/SmsApplication.java
index 62d3536..f10398f 100644
--- a/telephony/java/com/android/internal/telephony/SmsApplication.java
+++ b/telephony/java/com/android/internal/telephony/SmsApplication.java
@@ -48,6 +48,8 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
@@ -91,6 +93,7 @@
/**
* Name of this SMS app for display.
*/
+ @UnsupportedAppUsage
private String mApplicationName;
/**
@@ -191,7 +194,7 @@
* @return
*/
private static int getIncomingUserId(Context context) {
- int contextUserId = context.getUserId();
+ int contextUserId = UserHandle.myUserId();
final int callingUid = Binder.getCallingUid();
if (DEBUG_MULTIUSER) {
Log.i(LOG_TAG, "getIncomingUserHandle caller=" + callingUid + ", myuid="
@@ -224,6 +227,7 @@
* Implement ACTION_SENDTO intent.
* Support smsto Uri scheme.
*/
+ @UnsupportedAppUsage
public static Collection<SmsApplicationData> getApplicationCollection(Context context) {
return getApplicationCollectionAsUser(context, getIncomingUserId(context));
}
@@ -425,9 +429,6 @@
final SmsApplicationData smsApplicationData = receivers.get(packageName);
if (smsApplicationData != null) {
if (!smsApplicationData.isComplete()) {
- Log.w(LOG_TAG, "Package " + packageName
- + " lacks required manifest declarations to be a default sms app: "
- + smsApplicationData);
receivers.remove(packageName);
}
}
@@ -579,6 +580,7 @@
* Sets the specified package as the default SMS/MMS application. The caller of this method
* needs to have permission to set AppOps and write to secure settings.
*/
+ @UnsupportedAppUsage
public static void setDefaultApplication(String packageName, Context context) {
setDefaultApplicationAsUser(packageName, context, getIncomingUserId(context));
}
@@ -826,6 +828,7 @@
sSmsPackageMonitor.register(context, context.getMainLooper(), UserHandle.ALL, false);
}
+ @UnsupportedAppUsage
private static void configurePreferredActivity(PackageManager packageManager,
ComponentName componentName, int userId) {
// Add the four activity preferences we want to direct to this app.
@@ -868,6 +871,7 @@
* Returns SmsApplicationData for this package if this package is capable of being set as the
* default SMS application.
*/
+ @UnsupportedAppUsage
public static SmsApplicationData getSmsApplicationData(String packageName, Context context) {
Collection<SmsApplicationData> applications = getApplicationCollection(context);
return getApplicationForPackage(applications, packageName);
@@ -879,6 +883,7 @@
* @param updateIfNeeded update the default app if there is no valid default app configured.
* @return component name of the app and class to deliver SMS messages to
*/
+ @UnsupportedAppUsage
public static ComponentName getDefaultSmsApplication(Context context, boolean updateIfNeeded) {
return getDefaultSmsApplicationAsUser(context, updateIfNeeded, getIncomingUserId(context));
}
@@ -913,6 +918,7 @@
* @param updateIfNeeded update the default app if there is no valid default app configured.
* @return component name of the app and class to deliver MMS messages to
*/
+ @UnsupportedAppUsage
public static ComponentName getDefaultMmsApplication(Context context, boolean updateIfNeeded) {
int userId = getIncomingUserId(context);
final long token = Binder.clearCallingIdentity();
@@ -936,6 +942,7 @@
* @param updateIfNeeded update the default app if there is no valid default app configured.
* @return component name of the app and class to direct Respond Via Message intent to
*/
+ @UnsupportedAppUsage
public static ComponentName getDefaultRespondViaMessageApplication(Context context,
boolean updateIfNeeded) {
int userId = getIncomingUserId(context);
@@ -1036,6 +1043,7 @@
* <p>
* Caller must pass in the correct user context if calling from a singleton service.
*/
+ @UnsupportedAppUsage
public static boolean shouldWriteMessageForPackage(String packageName, Context context) {
if (SmsManager.getDefault().getAutoPersisting()) {
return true;
@@ -1050,6 +1058,7 @@
* @param packageName the name of the package to be checked
* @return true if the package is default sms app or bluetooth
*/
+ @UnsupportedAppUsage
public static boolean isDefaultSmsApplication(Context context, String packageName) {
if (packageName == null) {
return false;
diff --git a/telephony/java/com/android/internal/telephony/SmsHeader.java b/telephony/java/com/android/internal/telephony/SmsHeader.java
index 9fe1718..dd77b01 100644
--- a/telephony/java/com/android/internal/telephony/SmsHeader.java
+++ b/telephony/java/com/android/internal/telephony/SmsHeader.java
@@ -16,13 +16,12 @@
package com.android.internal.telephony;
-import com.android.internal.telephony.SmsConstants;
+import android.annotation.UnsupportedAppUsage;
+
import com.android.internal.util.HexDump;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
-
-import android.annotation.UnsupportedAppUsage;
import java.util.ArrayList;
/**
@@ -74,6 +73,10 @@
public static class PortAddrs {
@UnsupportedAppUsage
+ public PortAddrs() {
+ }
+
+ @UnsupportedAppUsage
public int destPort;
@UnsupportedAppUsage
public int origPort;
@@ -82,6 +85,10 @@
public static class ConcatRef {
@UnsupportedAppUsage
+ public ConcatRef() {
+ }
+
+ @UnsupportedAppUsage
public int refNumber;
@UnsupportedAppUsage
public int seqNumber;
diff --git a/telephony/java/com/android/internal/telephony/SmsMessageBase.java b/telephony/java/com/android/internal/telephony/SmsMessageBase.java
index ffdc4b6..f0687b4 100644
--- a/telephony/java/com/android/internal/telephony/SmsMessageBase.java
+++ b/telephony/java/com/android/internal/telephony/SmsMessageBase.java
@@ -16,18 +16,17 @@
package com.android.internal.telephony;
-import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
-import com.android.internal.telephony.SmsConstants;
-import com.android.internal.telephony.SmsHeader;
-import java.text.BreakIterator;
-import java.util.Arrays;
-
import android.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.provider.Telephony;
import android.telephony.SmsMessage;
import android.text.Emoji;
+import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
+
+import java.text.BreakIterator;
+import java.util.Arrays;
+
/**
* Base class declaring the specific methods and members for SmsMessage.
* {@hide}
@@ -102,6 +101,10 @@
@UnsupportedAppUsage
public int mMessageRef;
+ @UnsupportedAppUsage
+ public SmsMessageBase() {
+ }
+
// TODO(): This class is duplicated in SmsMessage.java. Refactor accordingly.
public static abstract class SubmitPduBase {
@UnsupportedAppUsage
diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
index dd9b242..ef485071 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
@@ -16,6 +16,8 @@
package com.android.internal.telephony;
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
/**
* Contains a list of string constants used to get or set telephone properties
* in the system. You can use {@link android.os.SystemProperties os.SystemProperties}
@@ -101,6 +103,7 @@
* provider of the SIM. 5 or 6 decimal digits.
* Availability: SIM state must be "READY"
*/
+ @UnsupportedAppUsage
static String PROPERTY_ICC_OPERATOR_NUMERIC = "gsm.sim.operator.numeric";
/** PROPERTY_ICC_OPERATOR_ALPHA is also known as the SPN, or Service Provider Name.
diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
index e2a8913b..6b3126d 100644
--- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
@@ -19,17 +19,17 @@
import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_IDP_STRING;
import android.content.res.Resources;
-import android.os.Parcel;
import android.os.SystemProperties;
import android.telephony.PhoneNumberUtils;
+import android.telephony.Rlog;
import android.telephony.SmsCbLocation;
import android.telephony.SmsCbMessage;
import android.telephony.cdma.CdmaSmsCbProgramData;
-import android.telephony.Rlog;
import android.text.TextUtils;
import android.util.Log;
import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
+import com.android.internal.telephony.Sms7BitEncodingTranslator;
import com.android.internal.telephony.SmsAddress;
import com.android.internal.telephony.SmsConstants;
import com.android.internal.telephony.SmsHeader;
@@ -43,7 +43,8 @@
import com.android.internal.telephony.uicc.IccUtils;
import com.android.internal.util.BitwiseInputStream;
import com.android.internal.util.HexDump;
-import com.android.internal.telephony.Sms7BitEncodingTranslator;
+
+import dalvik.annotation.compat.UnsupportedAppUsage;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
@@ -109,7 +110,9 @@
private static final int PRIORITY_URGENT = 0x2;
private static final int PRIORITY_EMERGENCY = 0x3;
+ @UnsupportedAppUsage
private SmsEnvelope mEnvelope;
+ @UnsupportedAppUsage
private BearerData mBearerData;
/** @hide */
@@ -119,15 +122,20 @@
createPdu();
}
+ @UnsupportedAppUsage
public SmsMessage() {}
public static class SubmitPdu extends SubmitPduBase {
+ @UnsupportedAppUsage
+ public SubmitPdu() {
+ }
}
/**
* Create an SmsMessage from a raw PDU.
* Note: In CDMA the PDU is just a byte representation of the received Sms.
*/
+ @UnsupportedAppUsage
public static SmsMessage createFromPdu(byte[] pdu) {
SmsMessage msg = new SmsMessage();
@@ -153,6 +161,7 @@
*
* @hide
*/
+ @UnsupportedAppUsage
public static SmsMessage createFromEfRecord(int index, byte[] data) {
try {
SmsMessage msg = new SmsMessage();
@@ -219,6 +228,7 @@
* Returns null on encode error.
* @hide
*/
+ @UnsupportedAppUsage
public static SubmitPdu getSubmitPdu(String scAddr, String destAddr, String message,
boolean statusReportRequested, SmsHeader smsHeader) {
return getSubmitPdu(scAddr, destAddr, message, statusReportRequested, smsHeader, -1);
@@ -239,6 +249,7 @@
* Returns null on encode error.
* @hide
*/
+ @UnsupportedAppUsage
public static SubmitPdu getSubmitPdu(String scAddr, String destAddr, String message,
boolean statusReportRequested, SmsHeader smsHeader, int priority) {
@@ -269,6 +280,7 @@
* address, if applicable, and the encoded message.
* Returns null on encode error.
*/
+ @UnsupportedAppUsage
public static SubmitPdu getSubmitPdu(String scAddr, String destAddr, int destPort,
byte[] data, boolean statusReportRequested) {
@@ -306,6 +318,7 @@
* address, if applicable, and the encoded message.
* Returns null on encode error.
*/
+ @UnsupportedAppUsage
public static SubmitPdu getSubmitPdu(String destAddr, UserData userData,
boolean statusReportRequested) {
return privateGetSubmitPdu(destAddr, statusReportRequested, userData);
@@ -322,6 +335,7 @@
* address, if applicable, and the encoded message.
* Returns null on encode error.
*/
+ @UnsupportedAppUsage
public static SubmitPdu getSubmitPdu(String destAddr, UserData userData,
boolean statusReportRequested, int priority) {
return privateGetSubmitPdu(destAddr, statusReportRequested, userData, priority);
@@ -393,6 +407,7 @@
}
/** Return true iff the bearer data message type is DELIVERY_ACK. */
+ @UnsupportedAppUsage
@Override
public boolean isStatusReportMessage() {
return (mBearerData.messageType == BearerData.MESSAGE_TYPE_DELIVERY_ACK);
@@ -415,6 +430,7 @@
* @param isEntireMsg indicates if this is entire msg or a segment in multipart msg
* @return TextEncodingDetails
*/
+ @UnsupportedAppUsage
public static TextEncodingDetails calculateLength(CharSequence messageBody,
boolean use7bitOnly, boolean isEntireMsg) {
CharSequence newMsgBody = null;
@@ -437,6 +453,7 @@
* {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_VMN},
* {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_WAP}
*/
+ @UnsupportedAppUsage
public int getTeleService() {
return mEnvelope.teleService;
}
@@ -448,6 +465,7 @@
* {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#MESSAGE_TYPE_BROADCAST},
* {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#MESSAGE_TYPE_ACKNOWLEDGE},
*/
+ @UnsupportedAppUsage
public int getMessageType() {
// NOTE: mEnvelope.messageType is not set correctly for cell broadcasts with some RILs.
// Use the service category parameter to detect CMAS and other cell broadcast messages.
@@ -680,6 +698,7 @@
/**
* Parses a SMS message from its BearerData stream.
*/
+ @UnsupportedAppUsage
public void parseSms() {
// Message Waiting Info Record defined in 3GPP2 C.S-0005, 3.7.5.6
// It contains only an 8-bit number with the number of messages waiting
@@ -816,6 +835,7 @@
* binder-call, and hence should be thread-safe, it has been
* synchronized.
*/
+ @UnsupportedAppUsage
public synchronized static int getNextMessageId() {
// Testing and dialog with partners has indicated that
// msgId==0 is (sometimes?) treated specially by lower levels.
@@ -840,6 +860,7 @@
* Creates BearerData and Envelope from parameters for a Submit SMS.
* @return byte stream for SubmitPdu.
*/
+ @UnsupportedAppUsage
private static SubmitPdu privateGetSubmitPdu(String destAddrStr, boolean statusReportRequested,
UserData userData) {
return privateGetSubmitPdu(destAddrStr, statusReportRequested, userData, -1);
@@ -1025,6 +1046,7 @@
/** This function shall be called to get the number of voicemails.
* @hide
*/
+ @UnsupportedAppUsage
public int getNumOfVoicemails() {
return mBearerData.numberOfMessages;
}
@@ -1036,6 +1058,7 @@
* @return byte array uniquely identifying the message.
* @hide
*/
+ @UnsupportedAppUsage
public byte[] getIncomingSmsFingerprint() {
ByteArrayOutputStream output = new ByteArrayOutputStream();
diff --git a/telephony/java/com/android/internal/telephony/cdma/UserData.java b/telephony/java/com/android/internal/telephony/cdma/UserData.java
index f879560..7187ae4 100644
--- a/telephony/java/com/android/internal/telephony/cdma/UserData.java
+++ b/telephony/java/com/android/internal/telephony/cdma/UserData.java
@@ -21,6 +21,8 @@
import com.android.internal.telephony.SmsHeader;
import com.android.internal.util.HexDump;
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
public class UserData {
/**
@@ -92,6 +94,7 @@
public static final int PRINTABLE_ASCII_MIN_INDEX = 0x20;
public static final int ASCII_NL_INDEX = 0x0A;
public static final int ASCII_CR_INDEX = 0x0D;
+ @UnsupportedAppUsage
public static final SparseIntArray charToAscii = new SparseIntArray();
static {
for (int i = 0; i < ASCII_MAP.length; i++) {
@@ -101,6 +104,10 @@
charToAscii.put('\r', ASCII_CR_INDEX);
}
+ @UnsupportedAppUsage
+ public UserData() {
+ }
+
/*
* TODO(cleanup): Move this very generic functionality somewhere
* more general.
@@ -131,12 +138,15 @@
/**
* Contains the data header of the user data
*/
+ @UnsupportedAppUsage
public SmsHeader userDataHeader;
/**
* Contains the data encoding type for the SMS message
*/
+ @UnsupportedAppUsage
public int msgEncoding;
+ @UnsupportedAppUsage
public boolean msgEncodingSet = false;
public int msgType;
@@ -146,13 +156,16 @@
*/
public int paddingBits;
+ @UnsupportedAppUsage
public int numFields;
/**
* Contains the user data of a SMS message
* (See 3GPP2 C.S0015-B, v2, 4.5.2)
*/
+ @UnsupportedAppUsage
public byte[] payload;
+ @UnsupportedAppUsage
public String payloadStr;
@Override
diff --git a/telephony/java/com/android/internal/telephony/cdma/BearerData.java b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
similarity index 99%
rename from telephony/java/com/android/internal/telephony/cdma/BearerData.java
rename to telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
index 9e6f19f..2181bc4 100644
--- a/telephony/java/com/android/internal/telephony/cdma/BearerData.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
@@ -17,10 +17,10 @@
package com.android.internal.telephony.cdma.sms;
import android.content.res.Resources;
+import android.telephony.Rlog;
import android.telephony.SmsCbCmasInfo;
import android.telephony.cdma.CdmaSmsCbProgramData;
import android.telephony.cdma.CdmaSmsCbProgramResults;
-import android.telephony.Rlog;
import com.android.internal.telephony.GsmAlphabet;
import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
@@ -31,6 +31,8 @@
import com.android.internal.util.BitwiseInputStream;
import com.android.internal.util.BitwiseOutputStream;
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
@@ -95,6 +97,7 @@
* (Special rules apply for WAP-messages.)
* (See 3GPP2 C.S0015-B, v2, 4.5.1)
*/
+ @UnsupportedAppUsage
public int messageId;
/**
@@ -106,7 +109,9 @@
public static final int PRIORITY_URGENT = 0x2;
public static final int PRIORITY_EMERGENCY = 0x3;
+ @UnsupportedAppUsage
public boolean priorityIndicatorSet = false;
+ @UnsupportedAppUsage
public int priority = PRIORITY_NORMAL;
/**
@@ -144,6 +149,7 @@
public static final int DISPLAY_MODE_USER = 0x2;
public boolean displayModeSet = false;
+ @UnsupportedAppUsage
public int displayMode = DISPLAY_MODE_DEFAULT;
/**
@@ -207,6 +213,7 @@
* presence of a UDH in the structured data, any existing setting
* will be overwritten.
*/
+ @UnsupportedAppUsage
public boolean hasUserDataHeader;
/**
@@ -214,6 +221,7 @@
* (e.g. padding bits, user data, user data header, etc)
* (See 3GPP2 C.S.0015-B, v2, 4.5.2)
*/
+ @UnsupportedAppUsage
public UserData userData;
/**
@@ -226,6 +234,10 @@
public boolean userResponseCodeSet = false;
public int userResponseCode;
+ @UnsupportedAppUsage
+ public BearerData() {
+ }
+
/**
* 6-byte-field, see 3GPP2 C.S0015-B, v2, 4.5.4
*/
@@ -244,6 +256,7 @@
private ZoneId mZoneId;
+ @UnsupportedAppUsage
public TimeStamp() {
mZoneId = ZoneId.systemDefault(); // 3GPP2 timestamps use the local timezone
}
@@ -295,6 +308,7 @@
}
}
+ @UnsupportedAppUsage
public TimeStamp msgCenterTimeStamp;
public TimeStamp validityPeriodAbsolute;
public TimeStamp deferredDeliveryTimeAbsolute;
@@ -383,6 +397,7 @@
private static class CodingException extends Exception {
+ @UnsupportedAppUsage
public CodingException(String s) {
super(s);
}
@@ -476,6 +491,7 @@
outStream.skip(3);
}
+ @UnsupportedAppUsage
private static int countAsciiSeptets(CharSequence msg, boolean force) {
int msgLen = msg.length();
if (force) return msgLen;
@@ -518,6 +534,7 @@
return ted;
}
+ @UnsupportedAppUsage
private static byte[] encode7bitAscii(String msg, boolean force)
throws CodingException
{
@@ -949,6 +966,7 @@
*
* @return byte array of raw encoded SMS bearer data.
*/
+ @UnsupportedAppUsage
public static byte[] encode(BearerData bData) {
bData.hasUserDataHeader = ((bData.userData != null) &&
(bData.userData.userDataHeader != null));
@@ -1200,6 +1218,7 @@
}
}
+ @UnsupportedAppUsage
private static void decodeUserDataPayload(UserData userData, boolean hasUserDataHeader)
throws CodingException
{
@@ -1845,6 +1864,7 @@
* @return the number of bits to read from the stream
* @throws CodingException if the specified encoding is not supported
*/
+ @UnsupportedAppUsage
private static int getBitsForNumFields(int msgEncoding, int numFields)
throws CodingException {
switch (msgEncoding) {
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSmsAddress.java b/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java
similarity index 97%
rename from telephony/java/com/android/internal/telephony/cdma/CdmaSmsAddress.java
rename to telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java
index d27a758..a82b975 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaSmsAddress.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java
@@ -16,11 +16,11 @@
package com.android.internal.telephony.cdma.sms;
+import android.annotation.UnsupportedAppUsage;
import android.util.SparseBooleanArray;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.SmsAddress;
-import com.android.internal.telephony.cdma.sms.UserData;
import com.android.internal.util.HexDump;
public class CdmaSmsAddress extends SmsAddress {
@@ -33,6 +33,7 @@
static public final int DIGIT_MODE_4BIT_DTMF = 0x00;
static public final int DIGIT_MODE_8BIT_CHAR = 0x01;
+ @UnsupportedAppUsage
public int digitMode;
/**
@@ -43,6 +44,7 @@
static public final int NUMBER_MODE_NOT_DATA_NETWORK = 0x00;
static public final int NUMBER_MODE_DATA_NETWORK = 0x01;
+ @UnsupportedAppUsage
public int numberMode;
/**
@@ -70,6 +72,7 @@
* This field shall be set to the number of address digits
* (See 3GPP2 C.S0015-B, v2, 3.4.3.3)
*/
+ @UnsupportedAppUsage
public int numberOfDigits;
/**
@@ -83,6 +86,7 @@
//static protected final int NUMBERING_PLAN_TELEX = 0x4;
//static protected final int NUMBERING_PLAN_PRIVATE = 0x9;
+ @UnsupportedAppUsage
public int numberPlan;
/**
@@ -91,6 +95,7 @@
* respectively.
*/
+ @UnsupportedAppUsage
public CdmaSmsAddress(){
}
@@ -194,6 +199,7 @@
* common punctuation. For alpha addresses, the string is cleaned
* up by removing whitespace.
*/
+ @UnsupportedAppUsage
public static CdmaSmsAddress parse(String address) {
CdmaSmsAddress addr = new CdmaSmsAddress();
addr.address = address;
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSmsSubaddress.java b/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsSubaddress.java
similarity index 100%
rename from telephony/java/com/android/internal/telephony/cdma/CdmaSmsSubaddress.java
rename to telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsSubaddress.java
diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsEnvelope.java b/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java
similarity index 96%
rename from telephony/java/com/android/internal/telephony/cdma/SmsEnvelope.java
rename to telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java
index de93b57..6af174c 100644
--- a/telephony/java/com/android/internal/telephony/cdma/SmsEnvelope.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java
@@ -17,7 +17,7 @@
package com.android.internal.telephony.cdma.sms;
-import com.android.internal.telephony.cdma.sms.CdmaSmsSubaddress;
+import android.annotation.UnsupportedAppUsage;
public final class SmsEnvelope {
/**
@@ -69,6 +69,7 @@
* or receiving the message.
* (See 3GPP2 C.S0015-B, v2, 3.4.3.1)
*/
+ @UnsupportedAppUsage
public int teleService = TELESERVICE_NOT_SET;
/**
@@ -76,6 +77,7 @@
* by the SMS message.
* (See 3GPP2 C.S0015-B, v2, 3.4.3.2)
*/
+ @UnsupportedAppUsage
public int serviceCategory;
/**
@@ -126,8 +128,10 @@
* encoded bearer data
* (See 3GPP2 C.S0015-B, v2, 3.4.3.7)
*/
+ @UnsupportedAppUsage
public byte[] bearerData;
+ @UnsupportedAppUsage
public SmsEnvelope() {
// nothing to see here
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSmsAddress.java b/telephony/java/com/android/internal/telephony/gsm/GsmSmsAddress.java
index bd8c83e..17f69b3 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmSmsAddress.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmSmsAddress.java
@@ -18,10 +18,13 @@
import android.telephony.PhoneNumberUtils;
-import java.text.ParseException;
import com.android.internal.telephony.GsmAlphabet;
import com.android.internal.telephony.SmsAddress;
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
+import java.text.ParseException;
+
public class GsmSmsAddress extends SmsAddress {
static final int OFFSET_ADDRESS_LENGTH = 0;
@@ -38,7 +41,7 @@
* (addressLength + 1) / 2"
* @throws ParseException
*/
-
+ @UnsupportedAppUsage
public GsmSmsAddress(byte[] data, int offset, int length) throws ParseException {
origBytes = new byte[length];
System.arraycopy(data, offset, origBytes, 0, length);
@@ -136,6 +139,7 @@
* address indicating a "set" of "indicator 1" of type "voice message
* waiting"
*/
+ @UnsupportedAppUsage
public boolean isCphsVoiceMessageSet() {
// 0x11 means "set" "voice message waiting" "indicator 1"
return isCphsVoiceMessageIndicatorAddress()
@@ -148,6 +152,7 @@
* address indicating a "clear" of "indicator 1" of type "voice message
* waiting"
*/
+ @UnsupportedAppUsage
public boolean isCphsVoiceMessageClear() {
// 0x10 means "clear" "voice message waiting" "indicator 1"
return isCphsVoiceMessageIndicatorAddress()
diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsCbHeader.java b/telephony/java/com/android/internal/telephony/gsm/SmsCbHeader.java
index 0dbc186..996edfc 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SmsCbHeader.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SmsCbHeader.java
@@ -19,6 +19,8 @@
import android.telephony.SmsCbCmasInfo;
import android.telephony.SmsCbEtwsInfo;
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
import java.util.Arrays;
/**
@@ -74,6 +76,7 @@
private final int mSerialNumber;
/** The Message Identifier in 3GPP is the same as the Service Category in CDMA. */
+ @UnsupportedAppUsage
private final int mMessageIdentifier;
private final int mDataCodingScheme;
@@ -90,6 +93,7 @@
/** CMAS warning notification info. */
private final SmsCbCmasInfo mCmasInfo;
+ @UnsupportedAppUsage
public SmsCbHeader(byte[] pdu) throws IllegalArgumentException {
if (pdu == null || pdu.length < PDU_HEADER_LENGTH) {
throw new IllegalArgumentException("Illegal PDU");
@@ -183,14 +187,17 @@
}
}
+ @UnsupportedAppUsage
int getGeographicalScope() {
return mGeographicalScope;
}
+ @UnsupportedAppUsage
int getSerialNumber() {
return mSerialNumber;
}
+ @UnsupportedAppUsage
int getServiceCategory() {
return mMessageIdentifier;
}
@@ -199,10 +206,12 @@
return mDataCodingScheme;
}
+ @UnsupportedAppUsage
int getPageIndex() {
return mPageIndex;
}
+ @UnsupportedAppUsage
int getNumberOfPages() {
return mNrOfPages;
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
index 5667387..5bb818b 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
@@ -16,18 +16,29 @@
package com.android.internal.telephony.gsm;
+import static com.android.internal.telephony.SmsConstants.ENCODING_16BIT;
+import static com.android.internal.telephony.SmsConstants.ENCODING_7BIT;
+import static com.android.internal.telephony.SmsConstants.ENCODING_8BIT;
+import static com.android.internal.telephony.SmsConstants.ENCODING_KSC5601;
+import static com.android.internal.telephony.SmsConstants.ENCODING_UNKNOWN;
+import static com.android.internal.telephony.SmsConstants.MAX_USER_DATA_BYTES;
+import static com.android.internal.telephony.SmsConstants.MAX_USER_DATA_SEPTETS;
+import static com.android.internal.telephony.SmsConstants.MessageClass;
+
+import android.content.res.Resources;
import android.telephony.PhoneNumberUtils;
import android.telephony.Rlog;
-import android.content.res.Resources;
import android.text.TextUtils;
import com.android.internal.telephony.EncodeException;
import com.android.internal.telephony.GsmAlphabet;
import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
-import com.android.internal.telephony.uicc.IccUtils;
+import com.android.internal.telephony.Sms7BitEncodingTranslator;
import com.android.internal.telephony.SmsHeader;
import com.android.internal.telephony.SmsMessageBase;
-import com.android.internal.telephony.Sms7BitEncodingTranslator;
+import com.android.internal.telephony.uicc.IccUtils;
+
+import dalvik.annotation.compat.UnsupportedAppUsage;
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
@@ -35,16 +46,6 @@
import java.time.LocalDateTime;
import java.time.ZoneOffset;
-import static com.android.internal.telephony.SmsConstants.MessageClass;
-import static com.android.internal.telephony.SmsConstants.ENCODING_UNKNOWN;
-import static com.android.internal.telephony.SmsConstants.ENCODING_7BIT;
-import static com.android.internal.telephony.SmsConstants.ENCODING_8BIT;
-import static com.android.internal.telephony.SmsConstants.ENCODING_16BIT;
-import static com.android.internal.telephony.SmsConstants.ENCODING_KSC5601;
-import static com.android.internal.telephony.SmsConstants.MAX_USER_DATA_SEPTETS;
-import static com.android.internal.telephony.SmsConstants.MAX_USER_DATA_BYTES;
-import static com.android.internal.telephony.SmsConstants.MAX_USER_DATA_BYTES_WITH_HEADER;
-
/**
* A Short Message Service message.
*
@@ -100,11 +101,18 @@
private static final int INVALID_VALIDITY_PERIOD = -1;
public static class SubmitPdu extends SubmitPduBase {
+ @UnsupportedAppUsage
+ public SubmitPdu() {}
+ }
+
+ @UnsupportedAppUsage
+ public SmsMessage() {
}
/**
* Create an SmsMessage from a raw PDU.
*/
+ @UnsupportedAppUsage
public static SmsMessage createFromPdu(byte[] pdu) {
try {
SmsMessage msg = new SmsMessage();
@@ -169,6 +177,7 @@
*
* @hide
*/
+ @UnsupportedAppUsage
public static SmsMessage createFromEfRecord(int index, byte[] data) {
try {
SmsMessage msg = new SmsMessage();
@@ -259,6 +268,7 @@
* Returns null on encode error.
* @hide
*/
+ @UnsupportedAppUsage
public static SubmitPdu getSubmitPdu(String scAddress,
String destinationAddress, String message,
boolean statusReportRequested, byte[] header) {
@@ -281,6 +291,7 @@
* Returns null on encode error.
* @hide
*/
+ @UnsupportedAppUsage
public static SubmitPdu getSubmitPdu(String scAddress,
String destinationAddress, String message,
boolean statusReportRequested, byte[] header, int encoding,
@@ -304,6 +315,7 @@
* Returns null on encode error.
* @hide
*/
+ @UnsupportedAppUsage
public static SubmitPdu getSubmitPdu(String scAddress,
String destinationAddress, String message,
boolean statusReportRequested, byte[] header, int encoding,
@@ -444,6 +456,7 @@
* @throws UnsupportedEncodingException
* @throws EncodeException if String is too large to encode
*/
+ @UnsupportedAppUsage
private static byte[] encodeUCS2(String message, byte[] header)
throws UnsupportedEncodingException, EncodeException {
byte[] userData, textPart;
@@ -478,6 +491,7 @@
* address, if applicable, and the encoded message.
* Returns null on encode error.
*/
+ @UnsupportedAppUsage
public static SubmitPdu getSubmitPdu(String scAddress,
String destinationAddress, String message,
boolean statusReportRequested) {
@@ -496,6 +510,7 @@
* address, if applicable, and the encoded message.
* Returns null on encode error.
*/
+ @UnsupportedAppUsage
public static SubmitPdu getSubmitPdu(String scAddress,
String destinationAddress, String message,
boolean statusReportRequested, int validityPeriod) {
@@ -576,6 +591,7 @@
* @param ret <code>SubmitPdu</code> containing the encoded SC
* address, if applicable, and the encoded message. Returns null on encode error.
*/
+ @UnsupportedAppUsage
private static ByteArrayOutputStream getSubmitPduHead(
String scAddress, String destinationAddress, byte mtiByte,
boolean statusReportRequested, SubmitPdu ret) {
@@ -622,12 +638,16 @@
}
private static class PduParser {
+ @UnsupportedAppUsage
byte mPdu[];
+ @UnsupportedAppUsage
int mCur;
SmsHeader mUserDataHeader;
byte[] mUserData;
+ @UnsupportedAppUsage
int mUserDataSeptetPadding;
+ @UnsupportedAppUsage
PduParser(byte[] pdu) {
mPdu = pdu;
mCur = 0;
@@ -667,6 +687,7 @@
/**
* returns non-sign-extended byte value
*/
+ @UnsupportedAppUsage
int getByte() {
return mPdu[mCur++] & 0xff;
}
@@ -808,6 +829,7 @@
*
* @return the user data payload, not including the headers
*/
+ @UnsupportedAppUsage
byte[] getUserData() {
return mUserData;
}
@@ -864,6 +886,7 @@
* @param byteCount the number of bytes in the user data payload
* @return a String with the decoded characters
*/
+ @UnsupportedAppUsage
String getUserDataUCS2(int byteCount) {
String ret;
@@ -912,6 +935,7 @@
* @param use7bitOnly ignore (but still count) illegal characters if true
* @return TextEncodingDetails
*/
+ @UnsupportedAppUsage
public static TextEncodingDetails calculateLength(CharSequence msgBody,
boolean use7bitOnly) {
CharSequence newMsgBody = null;
@@ -959,6 +983,7 @@
}
/** {@inheritDoc} */
+ @UnsupportedAppUsage
@Override
public boolean isMWIClearMessage() {
if (mIsMwi && !mMwiSense) {
@@ -970,6 +995,7 @@
}
/** {@inheritDoc} */
+ @UnsupportedAppUsage
@Override
public boolean isMWISetMessage() {
if (mIsMwi && mMwiSense) {
@@ -981,6 +1007,7 @@
}
/** {@inheritDoc} */
+ @UnsupportedAppUsage
@Override
public boolean isMwiDontStore() {
if (mIsMwi && mMwiDontStore) {
@@ -1000,12 +1027,14 @@
}
/** {@inheritDoc} */
+ @UnsupportedAppUsage
@Override
public int getStatus() {
return mStatus;
}
/** {@inheritDoc} */
+ @UnsupportedAppUsage
@Override
public boolean isStatusReportMessage() {
return mIsStatusReportMessage;
diff --git a/telephony/java/com/android/internal/telephony/uicc/IccUtils.java b/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
index 6b3df94..9c69e2d 100644
--- a/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
+++ b/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
@@ -24,6 +24,8 @@
import com.android.internal.telephony.GsmAlphabet;
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
import java.io.UnsupportedEncodingException;
/**
@@ -46,6 +48,7 @@
*
* Stops on invalid BCD value, returning string so far
*/
+ @UnsupportedAppUsage
public static String
bcdToString(byte[] data, int offset, int length) {
StringBuilder ret = new StringBuilder(length*2);
@@ -173,6 +176,7 @@
/**
* Decode cdma byte into String.
*/
+ @UnsupportedAppUsage
public static String
cdmaBcdToString(byte[] data, int offset, int length) {
StringBuilder ret = new StringBuilder(length);
@@ -208,6 +212,7 @@
* assume the digit is set to 0 but shall store the entire field
* exactly as received"
*/
+ @UnsupportedAppUsage
public static int
gsmBcdByteToInt(byte b) {
int ret = 0;
@@ -230,6 +235,7 @@
* is in the least significant nibble and the most significant
* is in the most significant nibble.
*/
+ @UnsupportedAppUsage
public static int
cdmaBcdByteToInt(byte b) {
int ret = 0;
@@ -281,6 +287,7 @@
* contain a 16 bit number which defines the complete 16 bit
* base pointer to a "half page" in the UCS2 code space...
*/
+ @UnsupportedAppUsage
public static String
adnStringFieldToString(byte[] data, int offset, int length) {
if (length == 0) {
@@ -372,6 +379,7 @@
return GsmAlphabet.gsm8BitUnpackedToString(data, offset, length, defaultCharset.trim());
}
+ @UnsupportedAppUsage
public static int
hexCharToInt(char c) {
if (c >= '0' && c <= '9') return (c - '0');
@@ -391,6 +399,7 @@
*
* @throws RuntimeException on invalid format
*/
+ @UnsupportedAppUsage
public static byte[]
hexStringToBytes(String s) {
byte[] ret;
@@ -417,6 +426,7 @@
*
* @return hex string representation of bytes array
*/
+ @UnsupportedAppUsage
public static String
bytesToHexString(byte[] bytes) {
if (bytes == null) return null;
@@ -444,6 +454,7 @@
* "offset" points to "octet 3", the coding scheme byte
* empty string returned on decode error
*/
+ @UnsupportedAppUsage
public static String
networkNameToString(byte[] data, int offset, int length) {
String ret;
@@ -494,6 +505,7 @@
* @param length The length of image body
* @return The bitmap
*/
+ @UnsupportedAppUsage
public static Bitmap parseToBnW(byte[] data, int length){
int valueIndex = 0;
int width = data[valueIndex++] & 0xFF;
@@ -536,6 +548,7 @@
* @param transparency with or without transparency
* @return The color bitmap
*/
+ @UnsupportedAppUsage
public static Bitmap parseToRGB(byte[] data, int length,
boolean transparency) {
int valueIndex = 0;
diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
index 232b5cb..c42201f 100644
--- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
@@ -35,8 +35,8 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.VersionedPackage;
-import android.net.NetworkStackClient;
-import android.net.NetworkStackClient.NetworkStackHealthListener;
+import android.net.ConnectivityModuleConnector;
+import android.net.ConnectivityModuleConnector.ConnectivityModuleHealthListener;
import android.os.Handler;
import android.os.test.TestLooper;
import android.provider.DeviceConfig;
@@ -86,11 +86,11 @@
private TestLooper mTestLooper;
private Context mSpyContext;
@Mock
- private NetworkStackClient mMockNetworkStackClient;
+ private ConnectivityModuleConnector mConnectivityModuleConnector;
@Mock
private PackageManager mMockPackageManager;
@Captor
- private ArgumentCaptor<NetworkStackHealthListener> mNetworkStackCallbackCaptor;
+ private ArgumentCaptor<ConnectivityModuleHealthListener> mConnectivityModuleCallbackCaptor;
@Before
public void setUp() throws Exception {
@@ -736,7 +736,7 @@
wd.startObservingHealth(observer, Collections.singletonList(APP_A), SHORT_DURATION);
// Notify of NetworkStack failure
- mNetworkStackCallbackCaptor.getValue().onNetworkStackFailure(APP_A);
+ mConnectivityModuleCallbackCaptor.getValue().onNetworkStackFailure(APP_A);
// Run handler so package failures are dispatched to observers
mTestLooper.dispatchAll();
@@ -782,18 +782,18 @@
Handler handler = new Handler(mTestLooper.getLooper());
PackageWatchdog watchdog =
new PackageWatchdog(mSpyContext, policyFile, handler, handler, controller,
- mMockNetworkStackClient);
+ mConnectivityModuleConnector);
// Verify controller is not automatically started
assertFalse(controller.mIsEnabled);
if (withPackagesReady) {
// Only capture the NetworkStack callback for the latest registered watchdog
- reset(mMockNetworkStackClient);
+ reset(mConnectivityModuleConnector);
watchdog.onPackagesReady();
// Verify controller by default is started when packages are ready
assertTrue(controller.mIsEnabled);
- verify(mMockNetworkStackClient).registerHealthListener(
- mNetworkStackCallbackCaptor.capture());
+ verify(mConnectivityModuleConnector).registerHealthListener(
+ mConnectivityModuleCallbackCaptor.capture());
}
return watchdog;
}
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
index 2c0432a..720c1af 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
@@ -929,7 +929,6 @@
*/
@Test
public void testBadUpdateRollback() throws Exception {
- BroadcastReceiver crashCountReceiver = null;
Context context = InstrumentationRegistry.getContext();
try {
InstallUtils.adoptShellPermissionIdentity(
@@ -937,7 +936,7 @@
Manifest.permission.DELETE_PACKAGES,
Manifest.permission.MANAGE_ROLLBACKS,
Manifest.permission.TEST_MANAGE_ROLLBACKS,
- Manifest.permission.KILL_BACKGROUND_PROCESSES,
+ Manifest.permission.FORCE_STOP_PACKAGES,
Manifest.permission.RESTART_PACKAGES);
RollbackManager rm = RollbackUtils.getRollbackManager();
@@ -967,7 +966,7 @@
RollbackBroadcastReceiver rollbackReceiver = new RollbackBroadcastReceiver();
// Crash TestApp.A PackageWatchdog#TRIGGER_FAILURE_COUNT times to trigger rollback
- crashCountReceiver = RollbackUtils.sendCrashBroadcast(context, TestApp.A, 5);
+ RollbackUtils.sendCrashBroadcast(TestApp.A, 5);
// Verify we received a broadcast for the rollback.
rollbackReceiver.take();
@@ -981,9 +980,6 @@
assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2);
} finally {
InstallUtils.dropShellPermissionIdentity();
- if (crashCountReceiver != null) {
- context.unregisterReceiver(crashCountReceiver);
- }
}
}
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
index db81831..9e6ac8e 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -25,7 +25,6 @@
import android.Manifest;
import android.annotation.Nullable;
-import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -77,7 +76,7 @@
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
Manifest.permission.TEST_MANAGE_ROLLBACKS,
- Manifest.permission.KILL_BACKGROUND_PROCESSES);
+ Manifest.permission.FORCE_STOP_PACKAGES);
}
/**
@@ -135,17 +134,8 @@
*/
@Test
public void testBadApkOnlyTriggerRollback() throws Exception {
- BroadcastReceiver crashCountReceiver = null;
- Context context = InstrumentationRegistry.getContext();
-
- try {
- // Crash TestApp.A PackageWatchdog#TRIGGER_FAILURE_COUNT times to trigger rollback
- crashCountReceiver = RollbackUtils.sendCrashBroadcast(context, TestApp.A, 5);
- } finally {
- if (crashCountReceiver != null) {
- context.unregisterReceiver(crashCountReceiver);
- }
- }
+ // Crash TestApp.A PackageWatchdog#TRIGGER_FAILURE_COUNT times to trigger rollback
+ RollbackUtils.sendCrashBroadcast(TestApp.A, 5);
// We expect the device to be rebooted automatically. Wait for that to
// happen. At that point, the host test driver will wait for the
diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java
index 8c522f4..c030c3e 100644
--- a/tests/net/java/com/android/server/connectivity/TetheringTest.java
+++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java
@@ -469,6 +469,8 @@
if (emulateInterfaceStatusChanged) {
assertEquals(1, mTetheringDependencies.isTetheringSupportedCalls);
verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
+ verify(mWifiManager).updateInterfaceIpState(
+ TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
}
verifyNoMoreInteractions(mNMService);
verifyNoMoreInteractions(mWifiManager);
@@ -534,6 +536,8 @@
verify(mNMService, times(1)).startTethering(any(String[].class));
verifyNoMoreInteractions(mNMService);
verify(mWifiManager).updateInterfaceIpState(
+ TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
+ verify(mWifiManager).updateInterfaceIpState(
TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
verifyNoMoreInteractions(mWifiManager);
verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_ACTIVE_LOCAL_ONLY);
@@ -554,6 +558,8 @@
.setInterfaceConfig(eq(TEST_WLAN_IFNAME), any(InterfaceConfiguration.class));
verify(mNMService, times(1)).stopTethering();
verify(mNMService, times(1)).setIpForwardingEnabled(false);
+ verify(mWifiManager, times(3)).updateInterfaceIpState(
+ TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
verifyNoMoreInteractions(mNMService);
verifyNoMoreInteractions(mWifiManager);
// Asking for the last error after the per-interface state machine
@@ -739,6 +745,8 @@
assertEquals(1, mTetheringDependencies.isTetheringSupportedCalls);
verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
+ verify(mWifiManager).updateInterfaceIpState(
+ TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
verifyNoMoreInteractions(mNMService);
verifyNoMoreInteractions(mWifiManager);
}
@@ -768,6 +776,8 @@
verify(mNMService, times(1)).startTethering(any(String[].class));
verifyNoMoreInteractions(mNMService);
verify(mWifiManager).updateInterfaceIpState(
+ TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
+ verify(mWifiManager).updateInterfaceIpState(
TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_TETHERED);
verifyNoMoreInteractions(mWifiManager);
verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_ACTIVE_TETHER);
@@ -805,6 +815,8 @@
.setInterfaceConfig(eq(TEST_WLAN_IFNAME), any(InterfaceConfiguration.class));
verify(mNMService, times(1)).stopTethering();
verify(mNMService, times(1)).setIpForwardingEnabled(false);
+ verify(mWifiManager, times(3)).updateInterfaceIpState(
+ TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
verifyNoMoreInteractions(mNMService);
verifyNoMoreInteractions(mWifiManager);
// Asking for the last error after the per-interface state machine
@@ -842,6 +854,8 @@
verify(mNetd, times(1)).interfaceSetCfg(argThat(p -> TEST_WLAN_IFNAME.equals(p.ifName)));
verify(mNMService, times(1)).tetherInterface(TEST_WLAN_IFNAME);
verify(mWifiManager).updateInterfaceIpState(
+ TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
+ verify(mWifiManager).updateInterfaceIpState(
TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_TETHERED);
// TODO: Figure out why this isn't exactly once, for sendTetherStateChangedBroadcast().
assertTrue(1 <= mTetheringDependencies.isTetheringSupportedCalls);
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index bbf71e7..99a686b 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -1084,7 +1084,8 @@
case OutputFormat::kProto: {
pb::ResourceTable pb_table;
- SerializeTableToPb(*table, &pb_table, context_->GetDiagnostics());
+ SerializeTableToPb(*table, &pb_table, context_->GetDiagnostics(),
+ options_.proto_table_flattener_options);
return io::CopyProtoToArchive(context_, &pb_table, kProtoResourceTablePath,
ArchiveEntry::kCompress, writer);
} break;
diff --git a/tools/aapt2/cmd/Link.h b/tools/aapt2/cmd/Link.h
index 324807c..56bff8f 100644
--- a/tools/aapt2/cmd/Link.h
+++ b/tools/aapt2/cmd/Link.h
@@ -24,6 +24,7 @@
#include "Resource.h"
#include "split/TableSplitter.h"
#include "format/binary/TableFlattener.h"
+#include "format/proto/ProtoSerialize.h"
#include "link/ManifestFixer.h"
#include "trace/TraceBuffer.h"
@@ -81,6 +82,7 @@
// Flattening options.
TableFlattenerOptions table_flattener_options;
+ SerializeTableOptions proto_table_flattener_options;
bool keep_raw_values = false;
// Split APK options.
@@ -245,9 +247,9 @@
"<add-resource> tags.",
&options_.auto_add_overlay);
AddOptionalSwitch("--override-styles-instead-of-overlaying",
- "Causes styles defined in -R resources to replace previous definitions\n"
- "instead of merging into them\n",
- &options_.override_styles_instead_of_overlaying);
+ "Causes styles defined in -R resources to replace previous definitions\n"
+ "instead of merging into them\n",
+ &options_.override_styles_instead_of_overlaying);
AddOptionalFlag("--rename-manifest-package", "Renames the package in AndroidManifest.xml.",
&options_.manifest_fixer_options.rename_manifest_package);
AddOptionalFlag("--rename-instrumentation-target-package",
@@ -283,13 +285,18 @@
AddOptionalSwitch("--strict-visibility",
"Do not allow overlays with different visibility levels.",
&options_.strict_visibility);
- AddOptionalSwitch("-v", "Enables verbose logging.", &verbose_);
- AddOptionalFlag("--trace-folder", "Generate systrace json trace fragment to specified folder.",
- &trace_folder_);
+ AddOptionalSwitch("--exclude-sources",
+ "Do not serialize source file information when generating resources in\n"
+ "Protobuf format.",
+ &options_.proto_table_flattener_options.exclude_sources);
+ AddOptionalFlag("--trace-folder",
+ "Generate systrace json trace fragment to specified folder.",
+ &trace_folder_);
AddOptionalSwitch("--merge-only",
- "Only merge the resources, without verifying resource references. This flag\n"
- "should only be used together with the --static-lib flag.",
- &options_.merge_only);
+ "Only merge the resources, without verifying resource references. This flag\n"
+ "should only be used together with the --static-lib flag.",
+ &options_.merge_only);
+ AddOptionalSwitch("-v", "Enables verbose logging.", &verbose_);
}
int Action(const std::vector<std::string>& args) override;
diff --git a/tools/aapt2/format/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp
index aa6547e..e4b3fce 100644
--- a/tools/aapt2/format/proto/ProtoSerialize.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize.cpp
@@ -290,8 +290,10 @@
pb::Overlayable* pb_overlayable = pb_table->add_overlayable();
pb_overlayable->set_name(overlayable_item.overlayable->name);
pb_overlayable->set_actor(overlayable_item.overlayable->actor);
- SerializeSourceToPb(overlayable_item.overlayable->source, source_pool,
- pb_overlayable->mutable_source());
+ if (source_pool != nullptr) {
+ SerializeSourceToPb(overlayable_item.overlayable->source, source_pool,
+ pb_overlayable->mutable_source());
+ }
}
pb::OverlayableItem* pb_overlayable_item = pb_entry->mutable_overlayable_item();
@@ -319,14 +321,17 @@
pb_overlayable_item->add_policy(pb::OverlayableItem::OEM);
}
- SerializeSourceToPb(overlayable_item.source, source_pool,
- pb_overlayable_item->mutable_source());
+ if (source_pool != nullptr) {
+ SerializeSourceToPb(overlayable_item.source, source_pool,
+ pb_overlayable_item->mutable_source());
+ }
pb_overlayable_item->set_comment(overlayable_item.comment);
}
void SerializeTableToPb(const ResourceTable& table, pb::ResourceTable* out_table,
- IDiagnostics* diag) {
- StringPool source_pool;
+ IDiagnostics* diag, SerializeTableOptions options) {
+ auto source_pool = (options.exclude_sources) ? nullptr : util::make_unique<StringPool>();
+
pb::ToolFingerprint* pb_fingerprint = out_table->add_tool_fingerprint();
pb_fingerprint->set_tool(util::GetToolName());
pb_fingerprint->set_version(util::GetToolFingerprint());
@@ -356,32 +361,40 @@
// Write the Visibility struct.
pb::Visibility* pb_visibility = pb_entry->mutable_visibility();
pb_visibility->set_level(SerializeVisibilityToPb(entry->visibility.level));
- SerializeSourceToPb(entry->visibility.source, &source_pool,
- pb_visibility->mutable_source());
+ if (source_pool != nullptr) {
+ SerializeSourceToPb(entry->visibility.source, source_pool.get(),
+ pb_visibility->mutable_source());
+ }
pb_visibility->set_comment(entry->visibility.comment);
if (entry->allow_new) {
pb::AllowNew* pb_allow_new = pb_entry->mutable_allow_new();
- SerializeSourceToPb(entry->allow_new.value().source, &source_pool,
- pb_allow_new->mutable_source());
+ if (source_pool != nullptr) {
+ SerializeSourceToPb(entry->allow_new.value().source, source_pool.get(),
+ pb_allow_new->mutable_source());
+ }
pb_allow_new->set_comment(entry->allow_new.value().comment);
}
if (entry->overlayable_item) {
- SerializeOverlayableItemToPb(entry->overlayable_item.value(), overlayables, &source_pool,
- pb_entry, out_table);
+ SerializeOverlayableItemToPb(entry->overlayable_item.value(), overlayables,
+ source_pool.get(), pb_entry, out_table);
}
for (const std::unique_ptr<ResourceConfigValue>& config_value : entry->values) {
pb::ConfigValue* pb_config_value = pb_entry->add_config_value();
SerializeConfig(config_value->config, pb_config_value->mutable_config());
pb_config_value->mutable_config()->set_product(config_value->product);
- SerializeValueToPb(*config_value->value, pb_config_value->mutable_value(), &source_pool);
+ SerializeValueToPb(*config_value->value, pb_config_value->mutable_value(),
+ source_pool.get());
}
}
}
}
- SerializeStringPoolToPb(source_pool, out_table->mutable_source_pool(), diag);
+
+ if (source_pool != nullptr) {
+ SerializeStringPoolToPb(*source_pool, out_table->mutable_source_pool(), diag);
+ }
}
static pb::Reference_Type SerializeReferenceTypeToPb(Reference::Type type) {
diff --git a/tools/aapt2/format/proto/ProtoSerialize.h b/tools/aapt2/format/proto/ProtoSerialize.h
index 33ffd18..7a3ea99 100644
--- a/tools/aapt2/format/proto/ProtoSerialize.h
+++ b/tools/aapt2/format/proto/ProtoSerialize.h
@@ -35,6 +35,11 @@
bool remove_empty_text_nodes = false;
};
+struct SerializeTableOptions {
+ /** Prevent serializing the source pool and source protos. */
+ bool exclude_sources = false;
+};
+
// Serializes a Value to its protobuf representation. An optional StringPool will hold the
// source path string.
void SerializeValueToPb(const Value& value, pb::Value* out_value, StringPool* src_pool = nullptr);
@@ -59,7 +64,8 @@
void SerializeConfig(const android::ConfigDescription& config, pb::Configuration* out_pb_config);
// Serializes a ResourceTable into its protobuf representation.
-void SerializeTableToPb(const ResourceTable& table, pb::ResourceTable* out_table, IDiagnostics* diag);
+void SerializeTableToPb(const ResourceTable& table, pb::ResourceTable* out_table,
+ IDiagnostics* diag, SerializeTableOptions options = {});
// Serializes a ResourceFile into its protobuf representation.
void SerializeCompiledFileToPb(const ResourceFile& file, pb::internal::CompiledFile* out_file);
diff --git a/tools/processors/staledataclass/Android.bp b/tools/processors/staledataclass/Android.bp
index c81d410..58a7d34 100644
--- a/tools/processors/staledataclass/Android.bp
+++ b/tools/processors/staledataclass/Android.bp
@@ -13,6 +13,8 @@
static_libs: [
"codegen-version-info",
],
+ // The --add-modules/exports flags below don't work for kotlinc yet, so pin this module to Java language level 8 (see b/139342589):
+ java_version: "1.8",
openjdk9: {
javacflags: [
"--add-modules=jdk.compiler",
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 20d772c..ca65736 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -50,6 +50,7 @@
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.WorkSource;
import android.util.Log;
import android.util.Pair;
@@ -1149,18 +1150,40 @@
* {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
* the standard {@link android.content.Context#WIFI_SERVICE Context.WIFI_SERVICE}.
* @param context the application context
- * @param service the Binder interface
* @hide - hide this because it takes in a parameter of type IWifiManager, which
* is a system private class.
*/
- public WifiManager(Context context, IWifiManager service, Looper looper) {
+ public WifiManager(Context context, Looper looper) {
mContext = context;
- mService = service;
mLooper = looper;
mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
+ }
+
+ /**
+ * This is used only for unit testing.
+ * @hide
+ */
+ @VisibleForTesting
+ public WifiManager(Context context, IWifiManager service, Looper looper) {
+ this(context, looper);
+ mService = service;
updateVerboseLoggingEnabledFromService();
}
+ private IWifiManager getIWifiManager() throws RemoteException {
+ if (mService == null) {
+ synchronized (this) {
+ mService = IWifiManager.Stub.asInterface(
+ ServiceManager.getService(Context.WIFI_SERVICE));
+ if (mService == null) {
+ throw new RemoteException("Wifi Service not running");
+ }
+ updateVerboseLoggingEnabledFromService();
+ }
+ }
+ return mService;
+ }
+
/**
* Return a list of all the networks configured for the current foreground
* user.
@@ -1201,7 +1224,7 @@
public List<WifiConfiguration> getConfiguredNetworks() {
try {
ParceledListSlice<WifiConfiguration> parceledList =
- mService.getConfiguredNetworks(mContext.getOpPackageName());
+ getIWifiManager().getConfiguredNetworks(mContext.getOpPackageName());
if (parceledList == null) {
return Collections.emptyList();
}
@@ -1217,7 +1240,7 @@
public List<WifiConfiguration> getPrivilegedConfiguredNetworks() {
try {
ParceledListSlice<WifiConfiguration> parceledList =
- mService.getPrivilegedConfiguredNetworks(mContext.getOpPackageName());
+ getIWifiManager().getPrivilegedConfiguredNetworks(mContext.getOpPackageName());
if (parceledList == null) {
return Collections.emptyList();
}
@@ -1249,13 +1272,13 @@
List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> configs = new ArrayList<>();
try {
Map<String, Map<Integer, List<ScanResult>>> results =
- mService.getAllMatchingFqdnsForScanResults(
+ getIWifiManager().getAllMatchingFqdnsForScanResults(
scanResults);
if (results.isEmpty()) {
return configs;
}
List<WifiConfiguration> wifiConfigurations =
- mService.getWifiConfigsForPasspointProfiles(
+ getIWifiManager().getWifiConfigsForPasspointProfiles(
new ArrayList<>(results.keySet()));
for (WifiConfiguration configuration : wifiConfigurations) {
Map<Integer, List<ScanResult>> scanResultsPerNetworkType = results.get(
@@ -1293,7 +1316,7 @@
return new HashMap<>();
}
try {
- return mService.getMatchingOsuProviders(scanResults);
+ return getIWifiManager().getMatchingOsuProviders(scanResults);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1320,7 +1343,7 @@
public Map<OsuProvider, PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders(
@NonNull Set<OsuProvider> osuProviders) {
try {
- return mService.getMatchingPasspointConfigsForOsuProviders(
+ return getIWifiManager().getMatchingPasspointConfigsForOsuProviders(
new ArrayList<>(osuProviders));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1405,7 +1428,7 @@
*/
private int addOrUpdateNetwork(WifiConfiguration config) {
try {
- return mService.addOrUpdateNetwork(config, mContext.getOpPackageName());
+ return getIWifiManager().addOrUpdateNetwork(config, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1631,7 +1654,7 @@
Looper looper = (handler == null) ? mContext.getMainLooper() : handler.getLooper();
Binder binder = new Binder();
try {
- mService.registerNetworkRequestMatchCallback(
+ getIWifiManager().registerNetworkRequestMatchCallback(
binder, new NetworkRequestMatchCallbackProxy(looper, callback),
callback.hashCode());
} catch (RemoteException e) {
@@ -1657,7 +1680,7 @@
Log.v(TAG, "unregisterNetworkRequestMatchCallback: callback=" + callback);
try {
- mService.unregisterNetworkRequestMatchCallback(callback.hashCode());
+ getIWifiManager().unregisterNetworkRequestMatchCallback(callback.hashCode());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1691,7 +1714,8 @@
public @NetworkSuggestionsStatusCode int addNetworkSuggestions(
@NonNull List<WifiNetworkSuggestion> networkSuggestions) {
try {
- return mService.addNetworkSuggestions(networkSuggestions, mContext.getOpPackageName());
+ return getIWifiManager().addNetworkSuggestions(
+ networkSuggestions, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1714,7 +1738,7 @@
public @NetworkSuggestionsStatusCode int removeNetworkSuggestions(
@NonNull List<WifiNetworkSuggestion> networkSuggestions) {
try {
- return mService.removeNetworkSuggestions(
+ return getIWifiManager().removeNetworkSuggestions(
networkSuggestions, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1760,7 +1784,8 @@
*/
public void addOrUpdatePasspointConfiguration(PasspointConfiguration config) {
try {
- if (!mService.addOrUpdatePasspointConfiguration(config, mContext.getOpPackageName())) {
+ if (!getIWifiManager().addOrUpdatePasspointConfiguration(
+ config, mContext.getOpPackageName())) {
throw new IllegalArgumentException();
}
} catch (RemoteException e) {
@@ -1783,7 +1808,8 @@
})
public void removePasspointConfiguration(String fqdn) {
try {
- if (!mService.removePasspointConfiguration(fqdn, mContext.getOpPackageName())) {
+ if (!getIWifiManager().removePasspointConfiguration(
+ fqdn, mContext.getOpPackageName())) {
throw new IllegalArgumentException();
}
} catch (RemoteException e) {
@@ -1806,7 +1832,7 @@
})
public List<PasspointConfiguration> getPasspointConfigurations() {
try {
- return mService.getPasspointConfigurations(mContext.getOpPackageName());
+ return getIWifiManager().getPasspointConfigurations(mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1826,7 +1852,7 @@
*/
public void queryPasspointIcon(long bssid, String fileName) {
try {
- mService.queryPasspointIcon(bssid, fileName);
+ getIWifiManager().queryPasspointIcon(bssid, fileName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1840,7 +1866,7 @@
*/
public int matchProviderWithCurrentNetwork(String fqdn) {
try {
- return mService.matchProviderWithCurrentNetwork(fqdn);
+ return getIWifiManager().matchProviderWithCurrentNetwork(fqdn);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1854,7 +1880,7 @@
*/
public void deauthenticateNetwork(long holdoff, boolean ess) {
try {
- mService.deauthenticateNetwork(holdoff, ess);
+ getIWifiManager().deauthenticateNetwork(holdoff, ess);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1884,7 +1910,7 @@
@Deprecated
public boolean removeNetwork(int netId) {
try {
- return mService.removeNetwork(netId, mContext.getOpPackageName());
+ return getIWifiManager().removeNetwork(netId, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1939,7 +1965,8 @@
boolean success;
try {
- success = mService.enableNetwork(netId, attemptConnect, mContext.getOpPackageName());
+ success = getIWifiManager().enableNetwork(
+ netId, attemptConnect, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1975,7 +2002,7 @@
@Deprecated
public boolean disableNetwork(int netId) {
try {
- return mService.disableNetwork(netId, mContext.getOpPackageName());
+ return getIWifiManager().disableNetwork(netId, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1998,7 +2025,7 @@
@Deprecated
public boolean disconnect() {
try {
- return mService.disconnect(mContext.getOpPackageName());
+ return getIWifiManager().disconnect(mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2022,7 +2049,7 @@
@Deprecated
public boolean reconnect() {
try {
- return mService.reconnect(mContext.getOpPackageName());
+ return getIWifiManager().reconnect(mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2046,7 +2073,7 @@
@Deprecated
public boolean reassociate() {
try {
- return mService.reassociate(mContext.getOpPackageName());
+ return getIWifiManager().reassociate(mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2132,7 +2159,7 @@
private long getSupportedFeatures() {
try {
- return mService.getSupportedFeatures();
+ return getIWifiManager().getSupportedFeatures();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2261,10 +2288,9 @@
* @hide
*/
public WifiActivityEnergyInfo getControllerActivityEnergyInfo() {
- if (mService == null) return null;
try {
synchronized(this) {
- return mService.reportActivityInfo();
+ return getIWifiManager().reportActivityInfo();
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -2304,7 +2330,7 @@
public boolean startScan(WorkSource workSource) {
try {
String packageName = mContext.getOpPackageName();
- return mService.startScan(packageName);
+ return getIWifiManager().startScan(packageName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2333,7 +2359,7 @@
*/
public WifiInfo getConnectionInfo() {
try {
- return mService.getConnectionInfo(mContext.getOpPackageName());
+ return getIWifiManager().getConnectionInfo(mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2347,7 +2373,7 @@
*/
public List<ScanResult> getScanResults() {
try {
- return mService.getScanResults(mContext.getOpPackageName());
+ return getIWifiManager().getScanResults(mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2366,7 +2392,7 @@
@Deprecated
public boolean isScanAlwaysAvailable() {
try {
- return mService.isScanAlwaysAvailable();
+ return getIWifiManager().isScanAlwaysAvailable();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2397,7 +2423,7 @@
*/
public void setCountryCode(@NonNull String country) {
try {
- mService.setCountryCode(country);
+ getIWifiManager().setCountryCode(country);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2411,12 +2437,12 @@
*/
@UnsupportedAppUsage
public String getCountryCode() {
- try {
- String country = mService.getCountryCode();
- return country;
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ try {
+ String country = getIWifiManager().getCountryCode();
+ return country;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
@@ -2427,7 +2453,7 @@
@UnsupportedAppUsage
public boolean isDualBandSupported() {
try {
- return mService.isDualBandSupported();
+ return getIWifiManager().isDualBandSupported();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2440,7 +2466,7 @@
*/
public boolean isDualModeSupported() {
try {
- return mService.needs5GHzToAnyApBandConversion();
+ return getIWifiManager().needs5GHzToAnyApBandConversion();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2453,7 +2479,7 @@
*/
public DhcpInfo getDhcpInfo() {
try {
- return mService.getDhcpInfo();
+ return getIWifiManager().getDhcpInfo();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2480,7 +2506,7 @@
@Deprecated
public boolean setWifiEnabled(boolean enabled) {
try {
- return mService.setWifiEnabled(mContext.getOpPackageName(), enabled);
+ return getIWifiManager().setWifiEnabled(mContext.getOpPackageName(), enabled);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2495,7 +2521,7 @@
*/
public int getWifiState() {
try {
- return mService.getWifiEnabledState();
+ return getIWifiManager().getWifiEnabledState();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2569,7 +2595,7 @@
*/
public void updateInterfaceIpState(String ifaceName, int mode) {
try {
- mService.updateInterfaceIpState(ifaceName, mode);
+ getIWifiManager().updateInterfaceIpState(ifaceName, mode);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2587,7 +2613,7 @@
*/
public boolean startSoftAp(@Nullable WifiConfiguration wifiConfig) {
try {
- return mService.startSoftAp(wifiConfig);
+ return getIWifiManager().startSoftAp(wifiConfig);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2602,7 +2628,7 @@
*/
public boolean stopSoftAp() {
try {
- return mService.stopSoftAp();
+ return getIWifiManager().stopSoftAp();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2671,7 +2697,7 @@
new LocalOnlyHotspotCallbackProxy(this, looper, callback);
try {
String packageName = mContext.getOpPackageName();
- int returnCode = mService.startLocalOnlyHotspot(
+ int returnCode = getIWifiManager().startLocalOnlyHotspot(
proxy.getMessenger(), new Binder(), packageName);
if (returnCode != LocalOnlyHotspotCallback.REQUEST_REGISTERED) {
// Send message to the proxy to make sure we call back on the correct thread
@@ -2723,7 +2749,7 @@
}
mLOHSCallbackProxy = null;
try {
- mService.stopLocalOnlyHotspot();
+ getIWifiManager().stopLocalOnlyHotspot();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2753,7 +2779,7 @@
Looper looper = (handler == null) ? mContext.getMainLooper() : handler.getLooper();
mLOHSObserverProxy = new LocalOnlyHotspotObserverProxy(this, looper, observer);
try {
- mService.startWatchLocalOnlyHotspot(
+ getIWifiManager().startWatchLocalOnlyHotspot(
mLOHSObserverProxy.getMessenger(), new Binder());
mLOHSObserverProxy.registered();
} catch (RemoteException e) {
@@ -2777,7 +2803,7 @@
}
mLOHSObserverProxy = null;
try {
- mService.stopWatchLocalOnlyHotspot();
+ getIWifiManager().stopWatchLocalOnlyHotspot();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2797,7 +2823,7 @@
@RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
public int getWifiApState() {
try {
- return mService.getWifiApEnabledState();
+ return getIWifiManager().getWifiApEnabledState();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2826,7 +2852,7 @@
@RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
public WifiConfiguration getWifiApConfiguration() {
try {
- return mService.getWifiApConfiguration();
+ return getIWifiManager().getWifiApConfiguration();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2843,7 +2869,8 @@
@RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE)
public boolean setWifiApConfiguration(WifiConfiguration wifiConfig) {
try {
- return mService.setWifiApConfiguration(wifiConfig, mContext.getOpPackageName());
+ return getIWifiManager().setWifiApConfiguration(
+ wifiConfig, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2858,7 +2885,7 @@
public void notifyUserOfApBandConversion() {
Log.d(TAG, "apBand was converted, notify the user");
try {
- mService.notifyUserOfApBandConversion(mContext.getOpPackageName());
+ getIWifiManager().notifyUserOfApBandConversion(mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2886,7 +2913,7 @@
*/
public void setTdlsEnabled(InetAddress remoteIPAddress, boolean enable) {
try {
- mService.enableTdls(remoteIPAddress.getHostAddress(), enable);
+ getIWifiManager().enableTdls(remoteIPAddress.getHostAddress(), enable);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2900,7 +2927,7 @@
*/
public void setTdlsEnabledWithMacAddress(String remoteMacAddress, boolean enable) {
try {
- mService.enableTdlsWithMacAddress(remoteMacAddress, enable);
+ getIWifiManager().enableTdlsWithMacAddress(remoteMacAddress, enable);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3189,8 +3216,8 @@
Looper looper = (handler == null) ? mContext.getMainLooper() : handler.getLooper();
Binder binder = new Binder();
try {
- mService.registerSoftApCallback(binder, new SoftApCallbackProxy(looper, callback),
- callback.hashCode());
+ getIWifiManager().registerSoftApCallback(
+ binder, new SoftApCallbackProxy(looper, callback), callback.hashCode());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3210,7 +3237,7 @@
Log.v(TAG, "unregisterSoftApCallback: callback=" + callback);
try {
- mService.unregisterSoftApCallback(callback.hashCode());
+ getIWifiManager().unregisterSoftApCallback(callback.hashCode());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3780,7 +3807,7 @@
public void disableEphemeralNetwork(String SSID) {
if (SSID == null) throw new IllegalArgumentException("SSID cannot be null");
try {
- mService.disableEphemeralNetwork(SSID, mContext.getOpPackageName());
+ getIWifiManager().disableEphemeralNetwork(SSID, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3824,7 +3851,7 @@
@UnsupportedAppUsage
private Messenger getWifiServiceMessenger() {
try {
- return mService.getWifiServiceMessenger(mContext.getOpPackageName());
+ return getIWifiManager().getWifiServiceMessenger(mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3884,10 +3911,10 @@
synchronized (mBinder) {
if (mRefCounted ? (++mRefCount == 1) : (!mHeld)) {
try {
- mService.acquireWifiLock(mBinder, mLockType, mTag, mWorkSource);
+ getIWifiManager().acquireWifiLock(mBinder, mLockType, mTag, mWorkSource);
synchronized (WifiManager.this) {
if (mActiveLockCount >= MAX_ACTIVE_LOCKS) {
- mService.releaseWifiLock(mBinder);
+ getIWifiManager().releaseWifiLock(mBinder);
throw new UnsupportedOperationException(
"Exceeded maximum number of wifi locks");
}
@@ -3917,7 +3944,7 @@
synchronized (mBinder) {
if (mRefCounted ? (--mRefCount == 0) : (mHeld)) {
try {
- mService.releaseWifiLock(mBinder);
+ getIWifiManager().releaseWifiLock(mBinder);
synchronized (WifiManager.this) {
mActiveLockCount--;
}
@@ -3980,7 +4007,7 @@
}
if (changed && mHeld) {
try {
- mService.updateWifiLockWorkSource(mBinder, mWorkSource);
+ getIWifiManager().updateWifiLockWorkSource(mBinder, mWorkSource);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4008,7 +4035,7 @@
synchronized (mBinder) {
if (mHeld) {
try {
- mService.releaseWifiLock(mBinder);
+ getIWifiManager().releaseWifiLock(mBinder);
synchronized (WifiManager.this) {
mActiveLockCount--;
}
@@ -4121,10 +4148,10 @@
synchronized (mBinder) {
if (mRefCounted ? (++mRefCount == 1) : (!mHeld)) {
try {
- mService.acquireMulticastLock(mBinder, mTag);
+ getIWifiManager().acquireMulticastLock(mBinder, mTag);
synchronized (WifiManager.this) {
if (mActiveLockCount >= MAX_ACTIVE_LOCKS) {
- mService.releaseMulticastLock(mTag);
+ getIWifiManager().releaseMulticastLock(mTag);
throw new UnsupportedOperationException(
"Exceeded maximum number of wifi locks");
}
@@ -4166,7 +4193,7 @@
synchronized (mBinder) {
if (mRefCounted ? (--mRefCount == 0) : (mHeld)) {
try {
- mService.releaseMulticastLock(mTag);
+ getIWifiManager().releaseMulticastLock(mTag);
synchronized (WifiManager.this) {
mActiveLockCount--;
}
@@ -4243,7 +4270,7 @@
*/
public boolean isMulticastEnabled() {
try {
- return mService.isMulticastEnabled();
+ return getIWifiManager().isMulticastEnabled();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4256,7 +4283,7 @@
@UnsupportedAppUsage
public boolean initializeMulticastFiltering() {
try {
- mService.initializeMulticastFiltering();
+ getIWifiManager().initializeMulticastFiltering();
return true;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -4281,7 +4308,7 @@
@UnsupportedAppUsage
public void enableVerboseLogging (int verbose) {
try {
- mService.enableVerboseLogging(verbose);
+ getIWifiManager().enableVerboseLogging(verbose);
} catch (Exception e) {
//ignore any failure here
Log.e(TAG, "enableVerboseLogging " + e.toString());
@@ -4296,7 +4323,7 @@
@UnsupportedAppUsage
public int getVerboseLoggingLevel() {
try {
- return mService.getVerboseLoggingLevel();
+ return getIWifiManager().getVerboseLoggingLevel();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4309,7 +4336,7 @@
*/
public void factoryReset() {
try {
- mService.factoryReset(mContext.getOpPackageName());
+ getIWifiManager().factoryReset(mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4323,7 +4350,7 @@
@UnsupportedAppUsage
public Network getCurrentNetwork() {
try {
- return mService.getCurrentNetwork();
+ return getIWifiManager().getCurrentNetwork();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4355,7 +4382,7 @@
*/
public void enableWifiConnectivityManager(boolean enabled) {
try {
- mService.enableWifiConnectivityManager(enabled);
+ getIWifiManager().enableWifiConnectivityManager(enabled);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4367,7 +4394,7 @@
*/
public byte[] retrieveBackupData() {
try {
- return mService.retrieveBackupData();
+ return getIWifiManager().retrieveBackupData();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4379,7 +4406,7 @@
*/
public void restoreBackupData(byte[] data) {
try {
- mService.restoreBackupData(data);
+ getIWifiManager().restoreBackupData(data);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4395,7 +4422,7 @@
@Deprecated
public void restoreSupplicantBackupData(byte[] supplicantData, byte[] ipConfigData) {
try {
- mService.restoreSupplicantBackupData(supplicantData, ipConfigData);
+ getIWifiManager().restoreSupplicantBackupData(supplicantData, ipConfigData);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4424,7 +4451,7 @@
throw new IllegalArgumentException("callback must not be null");
}
try {
- mService.startSubscriptionProvisioning(provider,
+ getIWifiManager().startSubscriptionProvisioning(provider,
new ProvisioningCallbackProxy(executor, callback));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -4538,7 +4565,7 @@
Looper looper = (handler == null) ? mContext.getMainLooper() : handler.getLooper();
Binder binder = new Binder();
try {
- mService.registerTrafficStateCallback(
+ getIWifiManager().registerTrafficStateCallback(
binder, new TrafficStateCallbackProxy(looper, callback), callback.hashCode());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -4558,7 +4585,7 @@
Log.v(TAG, "unregisterTrafficStateCallback: callback=" + callback);
try {
- mService.unregisterTrafficStateCallback(callback.hashCode());
+ getIWifiManager().unregisterTrafficStateCallback(callback.hashCode());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4614,7 +4641,7 @@
@RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
public String[] getFactoryMacAddresses() {
try {
- return mService.getFactoryMacAddresses();
+ return getIWifiManager().getFactoryMacAddresses();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4683,7 +4710,7 @@
@RequiresPermission(android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE)
public void setDeviceMobilityState(@DeviceMobilityState int state) {
try {
- mService.setDeviceMobilityState(state);
+ getIWifiManager().setDeviceMobilityState(state);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4738,8 +4765,9 @@
@NonNull EasyConnectStatusCallback callback) {
Binder binder = new Binder();
try {
- mService.startDppAsConfiguratorInitiator(binder, enrolleeUri, selectedNetworkId,
- enrolleeNetworkRole, new EasyConnectCallbackProxy(executor, callback));
+ getIWifiManager().startDppAsConfiguratorInitiator(
+ binder, enrolleeUri, selectedNetworkId, enrolleeNetworkRole,
+ new EasyConnectCallbackProxy(executor, callback));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4764,7 +4792,7 @@
@NonNull EasyConnectStatusCallback callback) {
Binder binder = new Binder();
try {
- mService.startDppAsEnrolleeInitiator(binder, configuratorUri,
+ getIWifiManager().startDppAsEnrolleeInitiator(binder, configuratorUri,
new EasyConnectCallbackProxy(executor, callback));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -4786,7 +4814,7 @@
public void stopEasyConnectSession() {
try {
/* Request lower layers to stop/abort and clear resources */
- mService.stopDppSession();
+ getIWifiManager().stopDppSession();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4885,7 +4913,7 @@
Log.v(TAG, "addOnWifiUsabilityStatsListener: listener=" + listener);
}
try {
- mService.addOnWifiUsabilityStatsListener(new Binder(),
+ getIWifiManager().addOnWifiUsabilityStatsListener(new Binder(),
new IOnWifiUsabilityStatsListener.Stub() {
@Override
public void onWifiUsabilityStats(int seqNum, boolean isSameBssidAndFreq,
@@ -4922,7 +4950,7 @@
Log.v(TAG, "removeOnWifiUsabilityStatsListener: listener=" + listener);
}
try {
- mService.removeOnWifiUsabilityStatsListener(listener.hashCode());
+ getIWifiManager().removeOnWifiUsabilityStatsListener(listener.hashCode());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4945,7 +4973,7 @@
@RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE)
public void updateWifiUsabilityScore(int seqNum, int score, int predictionHorizonSec) {
try {
- mService.updateWifiUsabilityScore(seqNum, score, predictionHorizonSec);
+ getIWifiManager().updateWifiUsabilityScore(seqNum, score, predictionHorizonSec);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}